Au gré de mes pérégrinations sur Github, j'ai trouvé un benchmark de serveur Web qui date un peu mais qui m'a interpelé.
J'avais déjà entendu parlé du langage Nim mais je le classais plutôt comme projet de recherche.
En regardant de plus près, je tombe sur une version 0.20 aboutie et un éco-système déjà très riche.
Nim se décrit comme un langage compilé statiquement typé qui propose également la méta-programmation (macros), un ramasse-miette, le "pattern-matching" fonctionnel et une compilation vers les langages C, C++, Objective-C ou JavaScript.
Le but affiché est d'être aussi rapide que le C, aussi expressif que le python et extensible comme du Lisp. Rien que ça! On est en droit d'être sceptique…
Or le langage a véritablement beaucoup d'attraits et la prise en main est quasi-immédiate surtout pour des personnes familières avec Python. Je vous propose quelques liens à la fin du journal pour parcourir plusieurs exemples de code.
Première évaluation
Mon premier objectif de test était de vouloir comparer bêtement la taille d'un exécutable avec une version de référence en C. Pour ce faire, je pars sur un équivalent classique à la commande /bin/true
de GNU Coreutils.
Le code d'exemple ne comprend qu'une seule ligne:
% cat ./true.nim
quit(QuitSuccess)
Compilation
La documentation dédiée à la compilation est très bien écrite et la commande de compilation est immédiate:
/tmp % nim c true.nim
Hint: used config file '/etc/nim/nim.cfg' [Conf]
Hint: system [Processing]
Hint: widestrs [Processing]
Hint: io [Processing]
Hint: true [Processing]
CC: stdlib_system.nim
CC: true.nim
Hint: [Link]
Hint: operation successful (14111 lines compiled; 0.479 sec total; 16.008MiB peakmem; Debug Build) [SuccessX]
% ls --human --size ./true /bin/true
88K ./true 36K /bin/true
Résultat plutôt logique pour un premier jet. Je peux améliorer la taille de l'exécutable final avec quelques options:
nim c -d:release --newruntime --opt:size true.nim
% ls --human --size ./true /bin/true
40K ./true 36K /bin/true
De mieux en mieux… et en regardant de plus près avec strace
, je vois que du code utilise une gestion des signaux désactivable avec l'option -d:noSignalHandler
. La documentation propose également de désactiver les vérifications "runtime" avec --checks:off
. Voyons ce que ça donne:
nim c --verbosity:2 -d:release --checks:off -d:noSignalHandler --newruntime --opt:size true.nim
% ls --human --size ./true /bin/true
% 20K ./true 36K /bin/true
Impressionnant! Nous sommes maintenant arrivés à une taille largement inférieure à ma version de référence.
Mais nous pouvons même faire encore mieux avec un dernier appel à la commande strip
…
% ls --size --human ./true =true
16K ./true 36K /bin/true
Dernier détail
Cependant un dernier détail me chiffonne avec la sortie de ldd
qui fait apparaître la librairie libdl.so.2
dans ma version. J'ai beau chercher avec les options de linkage passL:
mais je n'arrive pas à l'éviter.
Il ne me reste plus qu'à reprendre la ligne du compilateur présentée avec le mode verbose et ne pas établir manuellement ce lien:
% gcc -o /tmp/true .cache/nim/true_r/stdlib_allocators.nim.c.o .cache/nim/true_r/stdlib_system.nim.c.o .cache/nim/true_r/true.nim.c.o
% ldd ./true
linux-vdso.so.1 (0x00007fff5918e000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff1d239e000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff1d258a000)
Conclusion
Victoire! Mes sorties ldd
et strace
sont maintenant strictement identiques à la version GNU Coreutils mais j'ai gagné 45% sur mon exécutable final ;-)
Exemples de code Nim
J'ai essayé de classer les sites dans un ordre de progression:
- https://nim-by-example.github.io/
- https://narimiran.github.io/nim-basics/
- https://akehrer.github.io/posts/getting-started-with-nim/
- https://xmonader.github.io/nimdays/
- https://arthurtw.github.io/2015/01/12/quick-comparison-nim-vs-rust.html
- https://howistart.org/posts/nim/1/
Épilogue
La documentation du module system
précise que l'appel à quit
est implicite. Le fichier source true.nim
peut donc être vide pour le même résultat !
De plus, mon exemple est trop simpliste ici mais sachez que vous pouvez utiliser autre chose que gcc
très facilement. Par exemple:
nim c --gcc.exe:musl-gcc --gcc.linkerexe:musl-gcc ...
# Don't underestimate true
Posté par Colin Pitrat (site web personnel) . Évalué à 5.
C'est pas vraiment comparable à true quand même…
Chez moi,
/bin/true --help | --version
me donne de jolis messages, ta version be gère pas ça. Attention,true --help
ne fait rien (shell built-in).[^] # Re: Don't underestimate true
Posté par Vroum . Évalué à 3.
Effectivement, petite tricherie ;-) Le support des 2 options fait monter l'exécutable à 28K.
https://termbin.com/e8rag
[^] # Re: Don't underestimate true
Posté par Anonyme . Évalué à 7.
Encore plus léger :
Quoi ? Comment ça c’est pas comparable ? :p
[^] # Re: Don't underestimate true
Posté par Firwen (site web personnel) . Évalué à 3. Dernière modification le 04 juillet 2019 à 17:32.
Tu peux créer un PEX ( https://github.com/pantsbuild/pex ) ou un nix-bundle (https://github.com/matthewbauer/nix-bundle) pour une vrai comparaison.
Mais je suis pas sur que tu veuilles poster le résultat ^
[^] # Re: Don't underestimate true
Posté par Anonyme . Évalué à 2.
Haha, si si, carrément :
Ça doit sûrement être optimisable, mais je connais pas les « compilateurs Python ».
[^] # Re: Don't underestimate true
Posté par anaseto . Évalué à 4.
T'aurais pu te rattraper aussi en disant que tu copiais le true d'OpenBSD. Qui a besoin d'options non spécifiées par POSIX comme
--help
pourtrue
lorsqu'une page man détaillée existe pour cette commande si complexe ? :-) Par ailleurs, ça fait 10.2K chez moi.# bin true aux éditions O'reilly
Posté par octane . Évalué à 4.
Il est temps de mettre la référence à jour
http://www.miketaylor.org.uk/tech/oreilly/truenut.html
# 100% static link
Posté par devnewton 🍺 (site web personnel) . Évalué à 3.
Est-il possible de construire un exécutable sans aucune dépendance?
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
[^] # Re: 100% static link
Posté par gUI (Mastodon) . Évalué à 3.
Oui bien sûr, l'option
-static
de gcc sert à ça. Ou tu veux dire autre chose ?En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.
[^] # Re: 100% static link
Posté par abriotde (site web personnel, Mastodon) . Évalué à -1.
-static sert à ça mais il est néanmoins (quasi-?)impossible de se passer de certaines dépendances dont le noyau Linux.
Sous licence Creative common. Lisez, copiez, modifiez faites en ce que vous voulez.
[^] # Re: 100% static link
Posté par steph1978 . Évalué à 3.
ou alors tu pars sur un unikernel mais c'est un peu plus compliqué…
[^] # Re: 100% static link
Posté par Benjamin Henrion (site web personnel) . Évalué à 1.
Glibc casse délibérément le statique, bonne chance.
Sinon avec musl lindo ça fonctionne mieux.
Et les devs de Glibc ne le mentionne pas comme une fonctionnalité cassee.
[^] # Re: 100% static link
Posté par Kerro . Évalué à 4.
Quitte à exagérer tu aurais pu écrire qu'il est difficile de se passer de la dépendance au microcode du processeur, à un ordinateur, à l'électricité, etc.
[^] # Re: 100% static link
Posté par devnewton 🍺 (site web personnel) . Évalué à 3.
Comme en Go avec 0 dépendance (même pas libc).
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
[^] # Re: 100% static link
Posté par Anonyme . Évalué à 2.
T’es sûr de ça ? C’est des paramètres particulier à passer à
go build
? Parce que j’ai déjà compilé du Go sur Alpine et ça ne fonctionnait pas sur Debian (ou inversement).[^] # Re: 100% static link
Posté par devnewton 🍺 (site web personnel) . Évalué à 3.
C'est possible mais pas intuitif:
http://blog.wrouesnel.com/articles/Totally%20static%20Go%20builds/
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
# Pourquoi des exceptions?
Posté par Boiethios (site web personnel) . Évalué à 2.
Le langage supporte les "sum types": pourquoi avoir mis des exceptions au lieu du
Maybe
de Haskell ouOption
de Rust?[^] # Re: Pourquoi des exceptions?
Posté par Alex G. . Évalué à 3.
Peut être simplement parce qu'il y a des gens (comme moi) qui aiment bien le mécanisme des exceptions.
(mais je suis preneur de littérature pas trop complexe sur le sujet)
[^] # Re: Pourquoi des exceptions?
Posté par Nicolas Boulay (site web personnel) . Évalué à 6.
Ocaml a les 2. Et franchement, les exceptions c'est chiant. un type option/Sum t'oblige à gérer bien les cas, une exception fait semblant d'être simple, mais c'est difficile d'être sûr de tout gérer correctement.
"La première sécurité est la liberté"
[^] # Re: Pourquoi des exceptions?
Posté par reno . Évalué à 3.
Moui mais Walter Bright (le concepteur de D) te répondrait: qui va vérifier les messages de log?
Auquel j'ajouterai qui va vérifier les débordements entier?
Au lieu d'utiliser 1 + 2, tu vas faire utiliser une option?
[^] # Re: Pourquoi des exceptions?
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
Quel rapport avec les log ? Parce que c'est le comportement d'un code java typique ?
Les débordements d'entier sont rarement un problème :
- c'est une arithmétique de modulo qui ont des propriétés sympa
- les CPU n'ont pas de support pour le débordement, mais la propriété sympa
- C'est un problème de dimensionnement, un bug et pas un cas d'erreur.
"La première sécurité est la liberté"
[^] # Re: Pourquoi des exceptions?
Posté par reno . Évalué à 2.
Le rapport c'est que dans du code industriel, tu as beaucoup de log, donc quasiment toutes tes fonctions ont potentiellement des erreurs liés à ça.
Avec des exceptions, si tu as un problèmes de log ça n'est pas ignoré sans "surcout visuel" lié a la propagation des valeurs de retour..
Pour les débordements entier: l'arithmétique de modulo n'est quasiment jamais la sémantique que tu veux (les exceptions étant principalement la gestion des timers)
"- C'est un problème de dimensionnement, un bug et pas un cas d'erreur."
Hum, c'est un peu n'importe quoi cette phrase!
Ne pas poster tard le soir?
[^] # Re: Pourquoi des exceptions?
Posté par Nicolas Boulay (site web personnel) . Évalué à 5.
Je n'ai rien compris à ce que tu veux dire avec les log. En quoi le fait qu'il y en ai beaucoup ou pas à avoir avec la gestion d'exception ou l'usage de retour de fonction (type option ou autre).
Si tu as un code qui fait un dépassement d'entier, c'est que tu a un bug, et ce n'est pas un cas d'erreur à gérer. Les exceptions ne sont pas faite pour rattraper des bugs, mais de gérer des erreurs rares normales dans la vie du logiciel. Si tu as un dépassement, c'est qu'il une erreur dans les gestion des entrées de ton opération entière. C'est une problème de code faux, pas de gestion d'erreur dans l'usage du logiciel.
Il y a code connu en Ada qui gérait les exceptions entières, sans handler, cela a lancé l'autotest, ce qui a balancé des AAAA et des 5555 sur le bus. Et pouf la fusée, pour une variable dont tout le reste du code se foutait.
"La première sécurité est la liberté"
[^] # Re: Pourquoi des exceptions?
Posté par reno . Évalué à 2.
En théorie ça ne change rien, en pratique c'est important pour la lisibilité du code, si ton code nominal est noyé dans la gestion des code de retour..
Pour ton exemple: ce qui est valable pour une fusée ne vaut pas forcément pour le reste: se faire hacker a cause d'un débordement entier n'est pas un problème pour une fusée..
Et franchement faire la différence entre une erreur "file not found", "serveur unreachable" et un débordement entier, ça me parait TRES discutable.
[^] # Re: Pourquoi des exceptions?
Posté par Boiethios (site web personnel) . Évalué à 1.
Pour 1 + 2, le mieux c'est d'avoir le choix, comme avec Rust:
si on veut un comportement spécifique, on a tout un tas de méthodes:
[^] # Re: Pourquoi des exceptions?
Posté par reno . Évalué à 3.
Uniquement en mode release ça: en mode debug (le mode par défaut) il y a une panique.
[^] # Re: Pourquoi des exceptions?
Posté par Alex G. . Évalué à 2.
Oui mais là c'est une question de goût de ta part !
[^] # Re: Pourquoi des exceptions?
Posté par Nicolas Boulay (site web personnel) . Évalué à 4.
En fait, cela dépend si tu privilégie de torcher un code ou de faire un truc qui ne plante jamais.
"La première sécurité est la liberté"
[^] # Re: Pourquoi des exceptions?
Posté par fearan . Évalué à 3.
en même temps pour qu'un code ne plante jamais suffit juste que son temps de dev soit au moins égale à celui de l'abandon du projet ;)
Il ne faut pas décorner les boeufs avant d'avoir semé le vent
[^] # Re: Pourquoi des exceptions?
Posté par lolop (site web personnel) . Évalué à 4.
Il suffit de ne jamais l'exécuter.
Votez les 30 juin et 7 juillet, en connaissance de cause. http://www.pointal.net/VotesDeputesRN
[^] # Re: Pourquoi des exceptions?
Posté par devnewton 🍺 (site web personnel) . Évalué à 4.
J'aimerais bien un langage qui oblige à gérer toutes les erreurs possibles proprement. Bref pas d'unchecked exception, de panic ou autre.
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
[^] # Re: Pourquoi des exceptions?
Posté par reno . Évalué à 2.
Et bien vas-y: remplace tout les + de ton code par Add(int, int) -> nodiscardOption
et ajoute un attribut nodiscard devant toutes les fonctions.
A mon avis ça va être illisible rapidement..
[^] # Re: Pourquoi des exceptions?
Posté par jyes . Évalué à 4.
D’où le besoin exprimé par devnewton d’avoir un langage adapté plutôt que d’écrire du code illisible.
[^] # Re: Pourquoi des exceptions?
Posté par reno . Évalué à 2. Dernière modification le 05 juillet 2019 à 15:05.
Des propositions concrètes? Parce que là je ne vois pas..
Soit tu as une propagation automatiques des erreurs, ça s'appelle des exceptions, soit tu gère toi même les cas d'erreurs et là s'il faut gérer vraiment toutes les erreurs c'est très lourd.
[^] # Re: Pourquoi des exceptions?
Posté par devnewton 🍺 (site web personnel) . Évalué à 3. Dernière modification le 05 juillet 2019 à 15:37.
99% du temps (chiffre Dave Newton Institute Of Coding Horror), on veut juste que le nombre soit borné ou qu'il devienne invalide.
Donc je ferais un langage du style:
mutable compteur := int<0, 100>(99);
compteur += 2;
log.info(compteur); // affiche 100
mutable toto := number(42);
toto /= 0;
log.info(compteur); // affiche NaN
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
[^] # Re: Pourquoi des exceptions?
Posté par reno . Évalué à 2.
L'utilisation des additions saturées est très rare (sauf en traitement de signal) par contre l'utilisation de NaN pour éviter les exceptions/panic??
C'est sûr ça rend le flux d'exécution + simple, mais bon courage pour trouver l'endroit ou il y a eu le problème..
[^] # Re: Pourquoi des exceptions?
Posté par devnewton 🍺 (site web personnel) . Évalué à 3. Dernière modification le 05 juillet 2019 à 18:04.
Il y a plein de possibilités à réfléchir (si tu veux vraiment des exceptions, il faudrait au moins que le compilateur t'oblige à les gérer toutes), mais mon besoin est de faire des programmes qui ne plantent jamais salement.
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
[^] # Re: Pourquoi des exceptions?
Posté par reno . Évalué à 2.
Ça existe en Java le fait de devoir gérer toutes les exceptions mais beaucoup n'aime pas (ça me paraît une bonne idée mais je n'ai pas suffisamment utilisé Java pour savoir si ça marche bien en pratique)
[^] # Re: Pourquoi des exceptions?
Posté par devnewton 🍺 (site web personnel) . Évalué à 3.
Le compilateur t'oblige à gérer certaines exceptions, mais pas toutes.
https://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html
Go a fait exactement la même erreur avec les panics.
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
[^] # Re: Pourquoi des exceptions?
Posté par SpaceFox (site web personnel, Mastodon) . Évalué à 1.
Et à l'usage, le concept de checked exceptions a tellement d'inconvénients pour si peu d'avantages qu'il est généralement considéré comme l'un des défauts de Java.
La connaissance libre : https://zestedesavoir.com
[^] # Re: Pourquoi des exceptions?
Posté par devnewton 🍺 (site web personnel) . Évalué à 2.
Le problème c'est l'entre deux. Pour moi, soit tu es en train de faire un script jetable donc tu peux coder en mode yolo, soit tu fais un logiciel et là tu as envie de gérer tous les cas d'erreurs.
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
[^] # Re: Pourquoi des exceptions?
Posté par SpaceFox (site web personnel, Mastodon) . Évalué à 2.
Je vois deux soucis avec ça :
La connaissance libre : https://zestedesavoir.com
[^] # Re: Pourquoi des exceptions?
Posté par devnewton 🍺 (site web personnel) . Évalué à 5.
J'aime bien la solution de Go qui t'oblige à dire que tu t'en fous d'une erreur avec un underscore. Quand on lit le code, on comprends bien l'intention de l'auteur.
plop, err := refroidirReacteur()
if nil != err {
evacuerIleDeFrance()
}
resultat, _ := ploperSurLaTribune()
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
[^] # Re: Pourquoi des exceptions?
Posté par Nicolas Boulay (site web personnel) . Évalué à 4.
Dans le langage Esterel, à l'époque, il fallait utiliser des fonctions de troncature si on utilisait un "+" sur 2 registres 8 bits, le résultat était sur 9 bits, cela ne compilait pas, il fallait donc tronquer ou arrondir.
"La première sécurité est la liberté"
# il manque une ligne
Posté par refreketu . Évalué à 4.
On ne voit pas la commande en question dans le journal, est-ce que c'est un oubli ?
[^] # Re: il manque une ligne
Posté par Vroum . Évalué à 1.
Il s'agit de la commande usuelle
strip
qui prend en paramètre le fichier binaire. Elle est fournie en standard sur toutes les distributions. Elle te permet de diminuer la taille de ton exécutable en effaçant les symboles liés à la compilation.Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.