Elixir v1.20 : désormais un langage à typage progressif
(elixir-lang.org)- L’inférence de types et la vérification de types progressive s’appliquent à tous les programmes Elixir, ce qui permet de détecter du code mort et des bogues avérés qui échoueront forcément à l’exécution, même sans annotations de type
- Le type
dynamic(), contrairement àany()qui « autorise tout », suit à l’exécution l’éventail des types possibles et ne signale une violation que lorsqu’il ne recoupe pas du tout les types autorisés - Une valeur
dynamic(integer() or binary())ne déclenche pas de violation pour des appels où certaines possibilités se recoupent, comme des opérations numériques ou des fonctions de chaîne, mais en déclenche une pour des appels qui n’acceptent que des maps, commeMap.fetch! dynamic()se restreint selon la manière dont il est utilisé, et affinedataen une map de la forme%{..., a: number(), b: number()}dans du code commedata.a + data.b- Dans les guards, les unions, intersections et négations sont inférées, ce qui permet d’utiliser comme information de type des conditions comme
is_list,is_integer,is_map_key,not is_map_keyettuple_size - Les
caseet les conditionnels répercutent les informations des clauses précédentes sur les suivantes, en effectuant par exemple une vérification de type qui traite d’abordnil, puis restreint la valeur restante àbinary() - Des types ont été ajoutés à plusieurs fonctions de la bibliothèque standard liées aux tuples et aux maps, ce qui aide à repérer des clauses redondantes et du code mort dans les bases de code existantes
- Dans « If T: Benchmark for Type Narrowing », 12 catégories sur 13 sont validées, montrant qu’il est possible de retrouver des informations de type précises dans du code Elixir classique
- La v1.20 améliore de nouveau les temps de compilation des applications en environnement multicœur, et dans des benchmarks synthétiques, l’outil de build d’Elixir obtient les meilleurs résultats parmi les langages BEAM
- La nouvelle option du compilateur
:module_definitionpermet de choisir le mode d’exécution de la définition d’un module, avec la valeur par défaut:compiledou:interpreted, et s’active viaelixirc_options: [module_definition: :interpreted]dansmix.exs - L’option
:module_definitionn’affecte pas les fichiers.beamécrits sur disque et change uniquement le mode d’exécution à l’intérieur dedefmodule, ce qui peut aider à améliorer les temps de compilation dans les grands projets - Les nouvelles signatures de type s’appuyant sur les types ensemblistes devraient être discutées avec la définition de typed structs, une fois résolus les travaux sur les performances du système de types de la v1.20, les types récursifs, les types paramétrés et l’itération key-value des maps
1 commentaires
Avis sur Hacker News
C’est peut-être juste mon expérience personnelle, mais j’ai l’impression que si un langage n’a pas eu de types dès le départ, ça ne fonctionne jamais aussi bien qu’un vrai langage à typage statique
Je travaille comme développeur Elixir professionnel depuis une dizaine d’années et j’attendais depuis longtemps l’arrivée des types. Je suis vraiment ravi de voir que ce début est enfin là dans cette version
Cela dit, j’aimerais savoir comment l’état de v1.20 se compare à Dialyzer sans spécifications. Si je comprends bien, l’approche de success typing de Dialyzer se rapproche davantage de « s’il existe au moins une combinaison d’arguments qui fonctionne, on n’émet pas d’avertissement » que de « s’il existe une combinaison d’arguments susceptible d’échouer, on émet un avertissement », et je pensais qu’Elixir faisait ici quelque chose de similaire ; or je n’ai jamais trouvé Dialyzer particulièrement utile
J’ai vu passer plusieurs fois sur HN des articles sur le système de types progressif d’Elixir, sans vraiment les suivre en détail. Je me demande si quelqu’un sait si ce système de types progressif peut changer la complexité asymptotique d’un programme par rapport à du code non typé
À ma connaissance, la plupart des systèmes de types progressifs, comme Racket par exemple, peuvent rendre un programme asymptotiquement plus lent, avec quelques exceptions [1]
[1] https://doi.org/10.1145/3314221.3314627
La plupart des systèmes de types progressifs insèrent des contraintes quand une valeur franchit la frontière entre code typé et non typé. Par exemple, en vérifiant tous les éléments d’une liste ou en enveloppant une valeur dans un proxy de type. Mais l’équipe Elixir a publié le résultat strong arrows pour obtenir cette solidité sans ces vérifications à l’exécution, et le bytecode produit par le compilateur est sémantiquement identique à celui du code non typé
Ironiquement, les critiques disaient qu’il fallait des types, et les fans d’Elixir répondaient qu’il n’en fallait pas, qu’Elixir était magique d’une certaine manière et qu’il n’y avait donc pas de bugs liés aux types. Maintenant qu’ils ajoutent des types, ils trouvent des bugs. Ce n’était pas censé être inutile pour prévenir les bugs ? Cela reste malgré tout un bon changement. J’ai pas mal utilisé Elixir autrefois et j’aimais bien, mais il m’était difficile d’accepter l’absence de types
https://en.wiktionary.org/wiki/Goomba_fallacy
Je ne suis pas d’accord avec ce point de vue, mais c’est une position bien plus défendable que « $LANGUAGE est magique »
Avant les avancées de la théorie des types ensembliste, cette position était peut-être justifiée
Puis, au final, on ajoute le typage statique. C’est arrivé à Python, JavaScript et Ruby, et il y en a sûrement d’autres
J’adore le fait qu’on puisse mettre à jour Elixir sans changements cassants dans plusieurs projets, et que le compilateur trouve gratuitement des bugs. Je m’y suis trop habitué
Ça me fait vraiment plaisir à voir. On se rapproche maintenant vraiment du niveau de « grand langage », et pour moi Elixir est le premier candidat
Si vous connaissez un autre langage déjà agréable à utiliser et qui continue malgré cela à ajouter d’excellentes fonctionnalités de manière stable et sûre, je suis preneur. J’étais en train de bien maîtriser Go avant de me tourner vers l’apprentissage du C# avancé, parce que j’avais l’impression que Go avait cessé d’ajouter de bonnes fonctionnalités
J’ai suivi la piste Elixir sur exercism.io le mois dernier https://exercism.org/tracks/elixir
C’est vraiment excellent
Ah, ça recommence. Je vais sans doute réapprendre Elixir pendant encore un an
J’adore tout dans Elixir, mais plus que n’importe quel autre langage, Elixir me pousse à douter de moi-même en permanence. Mon cerveau ne semble pas fait pour le fonctionnel, mais ce changement me donne envie de réessayer
Ce qui est dommage, c’est qu’on ne peut pas vraiment dire que l’écosystème soit accueillant pour les débutants, et quand on répond aux questions, on part souvent du principe que la personne connaît déjà très bien le langage
Ne vous laissez pas tromper par le titre. La première moitié du livre, c’est simplement Elixir
Depuis 8 ans, à chaque fois que je me remets à Elixir, je reprends ce livre, et à chaque fois ça marche bien. Je ne l’ai jamais lu jusqu’au bout
L’un de mes critères pour juger si ce genre de livre de programmation en mode projet/tutoriel est bon, c’est de savoir s’il me donne déjà, vers le milieu, les outils pour aller faire mon vrai travail, même si je l’ai commencé plusieurs fois sans jamais le terminer
Mais à mon avis, ce n’est pas tant une question de cerveau pas adapté qu’un contraste entre le niveau d’expérience accumulé dans les langages impératifs et le fait de redevenir débutant dans un style purement fonctionnel
Ça ira de mieux en mieux. Le déclic qui m’a mis à l’aise avec la programmation fonctionnelle, ça a été de réaliser à quel point j’aimais assembler du code façon « one-liners » Bash bien aérés. Quand les données commencent sous une certaine forme, je les dump avec une commande, je réfléchis à l’étape qui les rapproche de la forme voulue, je les passe par un pipe vers la commande suivante, puis j’inspecte à nouveau. En continuant ainsi, on se retrouve généralement à la fin avec une suite de transformations de données qui ne les modifient pas en place
L’une des raisons pour lesquelles c’est confortable dans le shell, c’est qu’on se promène tous les jours dans le système de fichiers tout en accumulant du vocabulaire de commandes. Dans un environnement de type Unix, la bibliothèque de « fonctions » familières devient assez grande au fil des années. Dans un environnement de programmation purement fonctionnelle, il faut faire la même chose, mais apprendre le vocabulaire demande un peu plus d’effort. Les « commandes » qu’on utilise souvent deviennent des fonctions comme map, fold, zip au lieu de grep, cat, sort
Mais au fond, c’est vraiment la même chose, et l’attrait de construire des pipelines s’applique pareil des deux côtés. On peut avancer morceau par morceau, et à chaque étape du puzzle, oublier l’étape précédente pour se concentrer seulement sur la façon de transformer les données qu’on a sous les yeux. Cette faible charge contextuelle est rafraîchissante et confortable
J’espère vraiment que tu essaieras et que tu y prendras goût. C’est quand on apprend à apprécier le fait de ne pas encore savoir faire quelque chose qu’on finit par devenir bon
Bien sûr, je n’y ai passé que quelques après-midis, mais si je devais rééduquer mon cerveau au fonctionnel, je choisirais probablement Gleam pour ce sentiment de familiarité
Il y a parfois des messages qui n’attirent pas l’attention parce qu’ils sont flous, ou qu’on ignore parce qu’ils sentent le « faites mes devoirs à ma place »
Mais les messages qui traduisent une vraie curiosité reçoivent tous une réponse, de ce que j’ai vu
Excellent. En 1.20, la compilation de notre grosse application umbrella semble être devenue nettement plus rapide
Je me demande comment ça se compare à Gleam. Ou alors, pourquoi utiliser Elixir plutôt que Gleam maintenant ? J’imagine que Phoenix, et surtout LiveView, restent un gros atout pour Elixir
Je ne connais pas l’état actuel de Gleam OTP, mais la dernière fois que j’ai regardé, ce n’était pas terrible
Si tout t’est égal à part les types, alors prends Gleam. Mais dans ce cas, pourquoi ne pas simplement utiliser Rust ?
Par exemple, dans Gleam, le décodage/encodage JSON a tendance à devenir verbeux. En Rust, il suffit de dériver serde, et en Elixir, un simple appel de fonction suffit
Elixir a un écosystème plus mature. Par exemple, on peut utiliser Phoenix depuis Gleam, ou d’autres frameworks Gleam, mais l’expérience n’est pas la même
La grande raison pour laquelle Gleam attire plus qu’Elixir, ce sont les types, et Elixir est justement en train de réduire cet écart. Il y a aussi le fait qu’il puisse compiler vers JavaScript ; côté Elixir, Hologram fait quelque chose de similaire
Personnellement, je préfère le système de types de Gleam et sa syntaxe proche de Rust, mais pour l’instant, Elixir me semble être un meilleur choix pour tous mes projets de développement web