Sommaire
- Petit tour d'expérience sur des langages
- Ce qu'il m'est resté de tout ça
- Langages que j'aimerais creuser un peu un jour
Ces derniers temps, j'apprends moins de langages nouveaux qu'il y a quelques années. Du coup, je me suis dit que c'était une occasion de faire le tour sur l'essentiel des langages que j'ai testés.
Dans ce journal, je fais un peu dans le classique du ceci ou cela m'a plu dans tel langage, telle autre chose ne m'a pas plu. Le tout est très subjectif, biaisé et reflète fortement les trucs que j'ai voulu faire avec ces langages. Mais bon, j'ai lu beaucoup d'articles de blog dans ce genre (enfin, en général sur un seul langage, ou L1 vs L2) et, même si ça n'aide pas souvent à découvrir le langage de nos rêves, ni à changer d'opinion ou à apprendre grand-chose sur un langage qu'on connait déjà, j'ai trouvé quand même ça souvent sympa à lire vite fait, même (voire surtout) quand mon ressenti est différent.
Petit tour d'expérience sur des langages
OCaml
OCaml est le premier langage que j'ai appris ! (enfin, son prédécesseur Camllight initialement, le langage qui était utilisé qu'en prépas en France)
Les trucs que j'ai aimés :
- Compile vers du code natif assez efficace.
- Typage expressif (types algébriques), mais pratique (inférence de types) et pas trop compliqué : langage abordable.
- Mélange de code fonctionnel et impératif possible et plutôt facile.
- Sympa pour manipuler des structures de données arborescentes. En particulier pour écrire des analyses ou transformations d'AST.
- Documentation accessible en ligne de commande.
Les trucs qui me laissent dubitatif :
- Des messages d'erreur qui se sont améliorés mais, le typage riche et l'inférence n'aidant pas, les erreurs ont toujours du mal à parler la langue des mortels.
- Une syntaxe et un système de types pas trop compliqués, mais qui se compliquent ces dernières années : introduction des GADT (une sorte de types dépendants — en gros, des monstres surpuissants invoqués par des super héros) et les extensions de syntaxe ppx qui peuvent casser à chaque changement de version, entres autres; ça a du bon quand même.
- La syntaxe : l'extension Reason fait plus de modifications que strictement nécessaire, mais marquer clairement la fin des pattern matching et autres structures de contrôle (comme en Rust), ce serait déjà bien (après, des accolades ou un
end
comme en Coq ou Ruby, c'est du détail). - Pas besoin de préciser les bibliothèques utilisées en préambule de fichier.
- Un nombre ok de bibliothèques tierces.
Les trucs que j'ai moins aimés :
- Bibliothèque standard limitée, beaucoup de variantes de fonctions de base, mais peu au-delà (pas de compression, encodage, unicode, http). Au moins deux bibliothèques alternatives existent, mais elles résolvent surtout des soucis différents.
- Exceptions, en particulier leur sur-utilisation dans la bibliothèque standard qui a conduit à l'introduction de variantes en
*_opt
renvoyant plutôt un type option, du genreNone
ouSome x
, plutôt queNot_found
(mais pas pour toutes les fonctions encore). - Manque de structures de contrôle impératives : pas de break, continue, return ; ça peut vite devenir gênant si on manipule beaucoup les tableaux (tableaux qui d'ailleurs gagneraient en ergonomie à être dynamiques).
- Des fonctions non récursives terminales (donc risque de débordement de pile) dans la bibliothèque standard qui ont conduit à plus de duplication avec l'introduction de fonctions récursives terminales équivalentes.
- Les bibliothèques, à moins d'être très populaires, risquent d'être mal documentées : les types des fonctions, si on a de la chance une courte description pour chacune, parfois un exemple dans le README.
- Certaines bibliothèques connues font dans l'ingénierie lourde (comme le framework ocsigen), pas toujours évident de trouver des alternatives plus simples et bien documentées.
Haskell
Haskell a des propriétés similaires à OCaml, à ceci près qu'il accueille avec joie la complexité. Plus amusant, mais plus frustrant aussi.
Les trucs que j'ai aimés :
- Compile vers du code natif assez efficace.
- Typage expressif, inférence de type.
- Comme OCaml, pratique pour la manipulation d'AST.
- La bibliothèque [parsec](https://en.wikipedia.org/wiki/Parsec_(parser) qui permet de parser en combinant des parseurs. Des alternatives dans d'autres langages ont vu le jour, mais parsec reste plus naturel (mais pas le plus performant par contre).
Les trucs qui me laissent dubitatif :
- Les monades, des abstractions qui permettent de structurer les programmes de façon générique. C'est utilisé dans parsec pour combiner naturellement des parseurs, par exemple. Les monades IO et ST permettent de faire de l'impératif de façon compliquée aussi. C'est aussi utilisé pour rendre certains tutoriels très abstraits.
- Un système de types plus complexe que celui d'OCaml et qui rencontre plus tôt les limites de l'inférence. Et une pléthore d'extensions de langage optionnelles.
- Des messages d'erreur pour initiés à cause du typage expressif et de l'inférence de types.
- Une communauté intéressée par des concepts comme les monades, les flèches, les catégories, etc. Ça se reflète dans de nombreux tutoriels et échanges, tout comme dans les bibliothèques tierces. C'est plus dur de trouver des contenus qui font dans le pragmatique. Ce point devient positif si on est passionné par les concepts mentionnés, ou source de frustration autrement :-)
- Je n'aime pas trop certains éléments de syntaxe : l'indentation significative, l'abondance d'opérateurs avec priorités et associativité variables.
- Des préambules de fichier avec souvent une suite interminable d'imports de bibliothèques et un mélange d'imports avec noms qualifiés et non qualifiés.
Les trucs que j'ai moins aimés :
- Compilation lente.
- Possible mais difficile de faire de l'impératif : manipuler des tableaux est tout sauf agréable (par exemple pour représenter la carte dans un jeu, faire de la recherche de chemins, etc.).
- Il faut utiliser une bibliothèque externe pour avoir des chaînes de caractères implémentées raisonnablement.
- Beaucoup de bibliothèques, mais c'est pas facile de s'y retrouver.
- Beaucoup de bibliothèques font dans l'ingénierie lourde.
- Beaucoup de bibliothèques ont un arbre conséquent de dépendances.
- Beaucoup de bibliothèques sont mal documentées.
Exemple personnel : recherche d'une bibliothèque pour gérer le xml. Première tentative, hxt : pas moyen de trouver un indice dans la doc sur comment commencer (le théoricien remarquera que ça s'inspire de la théorie des flèches, mais ça l'aidera pas forcément tant que ça non plus). Deuxième tentative, HaXml : un peu moins abstrait peut-être, mais bon courage quand même. Troisième tentative, Text-XML-Light, le nom semble prometteur : pas d'exemples, mais ça semble en effet plus simple. Si l'on n'a pas encore capitulé, c'est le moment de chercher s'il n'y a pas un tutoriel à peu près à jour quelque part dans le wiki du langage pour une de ces bibliothèques.
Ceci dit, Haskell, c'est vraiment l'occasion de découvrir des concepts théoriques en faisant des trucs concrets, du genre découvrir à l'aide d'un framework web (appelé snap si ma mémoire est bonne) que les lentilles c'est pas seulement un truc qui se mange.
Tcl, Perl, Python, Raku
Tous ces langages se ressemblent un peu : typage dynamique, bases faciles à apprendre, plus ou moins d'OO, communauté pragmatique avec des écosystèmes de packages très variés, langages pas super performants mais suffisamment dans beaucoup de cas. Du coup, je vais parler uniquement des choses marquantes qui m'ont semblé uniques à chacun.
Pour Perl :
- Intégration des expressions régulières dans le langage, inspirée de Sed : erreurs dans la regexp à la compilation, plein de fonctionnalités sur l'Unicode.
- Mode de traitement de texte inspiré de Awk et adapté aux traitements rapides en ligne de commande.
- Une documentation commode en ligne de commande et qui permet de démarrer vite, avec beaucoup d'exemples dans un style un peu « recettes » en synopsis.
- Quelques incantations répétitives à écrire en début de chaque fichier.
- Un peu plus fonctionnel (fonctions anonymes, portée lexicale des variables).
- Mini typage statique partiel (scalaires vs tableaux vs tables de hachage, typos dans les noms de variables attrapées lors de la compilation).
Pour Python :
- Beaucoup de bibliothèques dans le domaine du calcul scientifique (numpy, etc.).
- Documentation plus OO que celle de Perl, plus orientée web que ligne de commande.
- Listes en compréhension (perso, j'aime pas trop, ça se démarque un peu du reste du langage).
Pour Tcl :
- Syntaxe où « tout est chaîne de caractères et commandes », mais fait proprement et sans pièges, contrairement au shell. Ça permet de faire des DSLs très naturels.
- Par exemple, l'intégration très sympa avec SQLite : on peut écrire
db eval {SELECT uid FROM table WHERE n <= $max AND time < $epoch}
en mettant directement les variables$max
et$epoch
dans la requête sans risquer d'injections SQL (c'est pas de l'interpolation en fait). Ça évite la typique redondance où il faut passer les arguments à la requête après, souvent avec le même nom. - Plus fragile aux typos que Perl ou Python.
- Intégration très naturelle avec Tk : mon langage préféré pour les petits GUI couplé à SQLite.
- Documentation sous forme de pages de manuel proches de celles des outils en ligne de commande : plus formelle que la documentation Perl.
- Wiki communautaire plein d'exemples, mais un peu chaotique.
- Écosystème plus petit que les autres : pas idéal pour faire du calcul scientifique, par exemple, et moins de choix en général (par exemple pour faire du web).
- Malgré son caractère de langage généraliste et bibliothèque standard assez vaste, Tcl peut être aussi facilement utilisé comme langage d'extension d'un programme en C (à la Lua).
Pour Raku (anciennement Perl 6) :
- Langage généraliste à tout faire très (trop ?) ambitieux et pas effrayé par la complexité.
- Langage plutôt cohérent et orthogonal, inspiré de Perl (mais aussi Ruby et d'autres), mais plus OO dans l'esprit.
- Les messages d'erreur sont plutôt sympas.
- Les expressions régulières sont intégrées dans un concept plus vaste de grammaires, très pratique pour écrire des parseurs.
- La VM se lance un peu lentement et les modules compilent pas vite non plus.
- Les expressions régulières, qui sont quand même fondamentales dans ce langage, étaient encore très mal optimisées il y a un ou deux ans, la dernière fois que j'ai testé.
- L'écosystème est assez jeune encore.
Common Lisp, Racket
Common Lisp et Racket sont des langages fonctionnels, par défaut au typage dynamique, ils se prêtent très bien à la manipulation de structures arborescentes et sont très prisés pour leur extensibilité à l'aide de systèmes de macros évolués. Les deux ont pas mal de bibliothèques tierces et compilent vers du code assez efficace (normalement moins que OCaml ou Haskell, mais nettement plus que Python ou Perl).
Pour Racket :
- Une documentation plus propre, surtout pour les bibliothèques tierces. Pour tout dire, lorsque j'ai testé, j'étais émerveillé par scribble, leur langage de documentation, qui est un dialecte de racket lui-même et permet de faire plein de validations sur la doc, dont le fait que les exemples compilent et renvoient le bon truc.
- Plus orienté fonctionnel, mais aussi plus académique : une partie de l'objectif du langage est d'illustrer les recherches en théorie des langages extensibles.
- Démarrage plus lent de la VM.
Pour Common Lisp :
- Macros plus simples, mais non hygiéniques (ce qui est pas cool par les temps qui courent).
- Un peu plus fonctionnel, en particulier la construction extrêmement flexible
loop
, ou peut-être encore mieux, la bibliothèque iterate : une macro d'itération très extensible ! - Un peu le bazar pour ce qui est des bibliothèques tierces : le gestionnaire de paquets lui-même, bien que fonctionnel, est considéré bêta depuis très très longtemps.
Si l'on veut juste apprendre afin de découvrir les macros pour faire des DSLs, c'est bien plus simple de faire ça avec Tcl.
J
J est un langage fonctionnel de manipulation vectorisée de tableaux multi-dimensionnels avec une syntaxe compacte faisant usage de primitives de haut niveau. C'est une variante moderne d'APL avec une syntaxe ASCII et plus de fonctionnalités.
Les trucs que j'ai aimés :
- La notation compacte est sympa pour expérimenter dans l'invite de commande.
- Les primitives du langage sont très génériques et flexibles.
- C'est amusant et ça fait réfléchir différemment à certains problèmes : je me suis amusé par exemple avec les problèmes du project euler, la génération de cartes et algos de dijkstra, ou l'écriture d'un automate pour parser des poèmes.
Les trucs que j'ai moins aimés :
- Lorsqu'un algorithme ne se prête pas bien à une vectorisation, ça devient un casse-tête infernal.
- J'ai beaucoup de mal à lire le code écrit par les autres.
- De manière générale, j'ai l'impression que ce langage a tendance à facilement faire saturer ma mémoire cognitive de travail : un langage idéal pour quand j'ai besoin de me sentir idiot, ça marche à chaque fois.
- Pour tout le code non algorithmique d'un projet, c'est aussi verbeux que n'importe quel langage et on ressent l'absence de structs/maps.
Le langage est surtout utilisé en statistiques et calcul scientifique, mais je dois dire que si j'avais un besoin dans ce domaine, je chercherais plutôt du côté de Python, R ou Julia. J'utilise J parfois comme calculatrice. En pratique je me contente souvent de la calculatrice dc
du standard POSIX :-)
Coq
Coq est un assistant de preuve et un langage purement fonctionnel que j'ai pas mal utilisé pendant la thèse dans le domaine de la compilation. Je suis resté simple utilisateur, assez ignorant des théories derrière et des techniques avancées d'automatisation de preuve. Il y a eu une dépêche ici il y a quelques années par des gens qui connaissent bien mieux le truc (perso, j'avais juste contribué avec un exemple).
Les trucs que j'ai aimés :
- C'est rigolo. Sérieusement, écrire des preuves de programme, c'est un peu comme un jeu, avec des moments de victoires épiques et de défaites accablantes.
- C'est un langage avec un système de types extrêmement expressif : imaginez par exemple pouvoir écrire à l'aide du système de types qu'une passe d'optimisation d'un compilateur ne change pas la sémantique d'un programme et n'introduit donc pas de bugs inattendus !
- Comme OCaml ou Haskell, le langage se prête bien à la manipulation d'AST et donc à l'écriture de compilateurs (avec des difficultés additionnelles ceci dit, comme le fait que les entiers sont représentés par un type algébrique et que Coq offre uniquement des structures de données purement fonctionnelles).
Les trucs qui me laissent dubitatif :
- Écrire du code propre est relativement facile, mais des preuves propres, c'est une autre histoire : il y a l'approche où on essaie d'automatiser un maximum, ce qui demande de connaître très bien le langage de tactiques (donc preuve compréhensible par moins de monde), d'avoir une machine puissante (automatisation signifie plus de travail pour Coq) et compromettre la maintenabilité (du genre preuve qui passe plus avec la version suivante de Coq); il y a l'approche où on automatise pas trop et écrit beaucoup de lemmes intermédiaires et des preuves parfois répétitives, on insiste jusqu'à ce que ça passe à force de sentiments forts : je faisais partie des utilisateurs chevronnés de cette technique de jeu.
Les trucs que j'ai moins aimés :
- Ça prend beaucoup de temps. Difficile de trouver des applications qui justifient cela, et ce même dans les domaines qui se prêtent assez bien à la preuve de programme (comme la compilation).
- Il faut utiliser un autre langage, généralement OCaml, pour les parties non purement fonctionnelles du programme qui font de l'I/O.
- C'est un langage complexe avec des messages d'erreur qui demandent une bonne expérience pour être appréhendés.
- Faut pas s'attendre à trouver des contributeurs dans la nature : les programmeurs Coq se trouvent tous ou presque dans le domaine de la recherche.
- Comme tout jeu, on finit par se lasser un peu à un moment et un jeu long dont on se lasse est un jeu qu'on ne finit pas (à moins d'être payé pour).
- Les ressources disponibles dans la nature pour apprendre sont limitées, souvent écrites pour des gens qui font une thèse et sont intéressés par la théorie. La pratique et les astuces de preuve, faut les apprendre soi-même ou lors d'échanges avec les collègues si on a la chance d'être dans un environnement Coq. Bref, c'est peu accessible.
Go
Go est un langage que j'utilise beaucoup ces derniers temps (frundis, jeux, des petits scripts), je suis plutôt satisfait.
Les trucs que j'ai aimés :
- Compile vers du code natif efficace. Compilation rapide, statique par défaut.
- Langage : structures de contrôle impératives flexibles (for, switch, break, continue, labels de boucle), les essentiels du fonctionnel (fonctions de première classe et clôtures lexicales), l'essentiel de l'OO (structs, méthodes et interfaces, pas de classes), l'essentiel du typage statique (typage moyennement expressif, mais flexible au besoin et sans conversions implicites ni inférences trop génériques qui compliquent les messages d'erreur), l'essentiel des structures de données (maps et tableaux dynamiques, comme avec Perl, Python ou Ruby).
- Une bibliothèque standard fournie, mais abordable et bien documentée.
- Beaucoup de bibliothèques tierces bien documentées, souvent avec peu ou pas de dépendances.
- Crosscompilation facile pour les programmes en pur Go (avec export en WebAssembly facile).
- Programmation concurrente facile avec les channels et goroutines.
- Un package, c'est tous les fichiers d'un dossier: pas besoin de faire un package différent pour éviter d'avoir trop de trucs dans un même fichier.
- Documentation accessible en ligne de commande et, en général, langage pratique à utiliser dans un terminal avec plein d'outils (renommages, analyses statiques, bonne intégration vim/emacs, etc.).
Les trucs qui me laissent dubitatif :
- URLs pour les noms d'import de package : ça conduit à devoir modifier le code si on change l'hébergement du projet. Ceci dit, le packaging n'a pas de solution magique non plus : j'ai beau ne pas vraiment aimer cette idée, c'est souvent pratique et pas clairement pire que les alternatives sur tous les points.
- Absence de types génériques (en cours d'être résolue, peut-être pour dans un an ou deux) : ça serait bien dans certains cas (bibliothèques génériques pour structures de données complexes ou opérations génériques sur des channels), mais ça me manque assez rarement tout compte fait (je ne ressens pas le besoin de remplacer les boucles
for
par des fonctions génériques, par exemple). - Plus verbeux qu'un langage dynamique, essentiellement du fait des signatures de fonctions (en pratique rentable dans un projet qui va au-delà du script, je trouve).
Les trucs que j'ai moins aimés :
- Difficile parfois de faire du pur Go (GUI, SQLite, etc.) : l'avantage de la crosscompilation facile disparaît dans ce cas. C'est pas vraiment un point négatif, mais une annulation courante de point positif.
Rust
Rust est un langage qui a pas mal de popularité en ce moment, pas mal de trucs sont passés sur linuxfr. J'ai lu un tutoriel, testé des exemples et lu de la doc, mais je n'ai jamais vraiment programmé avec, donc voici plutôt un retour d'apprentissage et d'utilisation :
- Des programmes très performants, dont le génial ripgrep qui remplace avantageusement grep.
- Des programmes avec beaucoup de dépendances et qui mettent beaucoup de temps à compiler.
- Langage d'inspirations multiples avec typage assez expressif (types somme et filtrage par motif similaires à OCaml), des traits (mais sans classes, un peu comme en Go).
- Langage qui facilite l'impératif et le fonctionnel, même si l'absence de GC rend certaines pratiques de programmation fonctionnelle (comme une fonction qui renvoie une fonction) un peu alambiquées à écrire.
- Un peu complexe à apprendre du fait de quelques notions assez subtiles (ownership, borrowing) qui facilitent l'écriture de programmes concurrents memory safe, et du fait de l'ampleur du langage (macros, etc.).
- Une documentation orientée web (même s'il me semble que j'avais trouvé un outil non officiel en ligne de commande).
J'aimerais m'y mettre un jour, mais j'ai pas d'idée de projet personnel qui profite de l'absence de GC : un peu comme pour le C et le C++, avec la différence qu'avec ceux-ci je me suis déjà retrouvé à devoir lire voire modifier du code dans les programmes que j'utilise, et ça ne m'est pas encore arrivé avec du Rust.
Ce qu'il m'est resté de tout ça
Au final, aujourd'hui, les seuls langages que j'utilise vraiment encore sont Go (pour un peu tout), Tcl (pour les GUIs et SQLite) et Perl (pour les petits scripts et CPAN). C'est sans compter des petits bouts de Javascript (dont j'ai pas parlé, car j'ai juste écrit des petits trucs en vanilla avec la doc de mozilla, sans aller chercher quoi que ce soit dans l'écosystème), ou les modifs de code C/C++ pour compiler sous OpenBSD, et mes tentatives le plus souvent couronnées d'échec pour compiler puis lancer du Java (dernière défaite cuisante en date : le jeu Mindustry qui est passé en dépêche il y a peu).
Ceci dit, même si au final on peut se dire à quoi bon avoir exploré autant de langages, j'ai bon souvenir de tout ça et ça influe probablement sur ma façon de programmer, j'espère qu'en bien :-)
Langages que j'aimerais creuser un peu un jour
Un langage relativement nouveau qui m'a l'air intéressant est txr : c'est en fait la combinaison de deux langages, un langage qui permet de capturer des motifs et parser facilement des documents, inspiré d'Awk, et un langage au style Lisp, mais différent. C'est pas un petit langage !
Dans le domaine des langages logiques, je trouve curieux Mercury, qui est un langage inspiré de Prolog pour la partie logique, et Haskell pour la partie typage.
Pour ce qui est des langages concaténatifs, inspirés de Forth, Factor semble être une approche moderne intéressante. Ceci dit, mes quelques lectures de tutos me donnent l'impression que mon cerveau ne gère pas bien l'approche concaténative de pile dès que ça devient un peu complexe (un peu la même sensation qu'avec J, mais pas aussi marquée).
J'ai vu passer assez souvent des articles sur le langage assez jeune mais plutôt actif Zig. Je me demande comment il se ressent en pratique par rapport au C voire au Rust ou C++.
# Erlang/Elixir
Posté par Guillaume Denry (site web personnel) . Évalué à 7.
Je te recommande également de te pencher sur Elixir et Erlang qui proposent de puissants outils pour faire de la programmation concurrente (et fonctionnelle).
[^] # Re: Erlang/Elixir
Posté par anaseto . Évalué à 2.
C'est vrai, j'avais regardé à quoi ressemblait Elixir à un moment, sauf qu'à l'époque la programmation concurrente me disait pas grande chose, du coup je suis passé à côté.
# Mon favoRi !
Posté par _kaos_ . Évalué à 4.
Salut,
D'autres en ont parlé ici, moi également, je trouve R super, et je crois qu'il manque à ta liste.
La courbe d'apprentissage est assez rude, ça, c'est indéniable.
Par contre, comme c'est un langage vectoriel, c'est super compact.
Matricule 23415
# un langage pour des petits GUI
Posté par Nicolas Boulay (site web personnel) . Évalué à 7.
Est-ce que vous connaissez un langage pour faire rapidement une GUI ? J'ai testé le Tcl/Tk il y a très longtemps, mais je n'avais pas aimé.
"La première sécurité est la liberté"
[^] # Re: un langage pour des petits GUI
Posté par raphj . Évalué à 8.
Python + Qt, peut-être ?
[^] # Re: un langage pour des petits GUI
Posté par Eh_Dis_Mwan . Évalué à 6.
Pythion +tkinter est beaucoup plus aisé
[^] # Re: un langage pour des petits GUI
Posté par Philippe F (site web personnel) . Évalué à 3.
Python + Qt sans hésiter! Beaucoup plus simple d'approche et mieux documenté que tkinter . Et ca tiendra encore la route si le petit GUI se transforme en grosse application!
[^] # Re: un langage pour des petits GUI
Posté par Eh_Dis_Mwan . Évalué à 2.
c'est sûr que tkinter est assez moche et assez limité, mais autant j'arrive à peu près à faire des trucs en tkinter , autant saavec 0 connaissances en prog GUI par événement, la programmation QT est assez compliqu, u plutôt mal documenté, reservé à une élite
[^] # Re: un langage pour des petits GUI
Posté par Aldebaran (site web personnel) . Évalué à 3.
Je fais pas mal de Qt et je suis loin de faire partie de l'élite ^
Tant qu'à donner mon avis, mon langage favoris d'interface en ce moment c'est le qml, c'est déclaratif et plutôt chouette avec son scripting en pseudo js (+ la possibilité d'interagir avec du code c++).
Sinon je vais bientôt tester d'écrire une app avec Tauri (un genre d'electron léger) donc en html/js/css. Avec les techno web on fait quand même de belles gui.
D'ailleurs histoire de parler d'un truc que j'aime bien, je voulais essayer d’intégrer une app que j'ai codé avec Yew dans un runtime Tauri. Yew c'est le feu, ça me rappel beaucoup Vue.js .
[^] # Re: un langage pour des petits GUI
Posté par raphj . Évalué à 2.
Je développe pas mal avec les technos du web. En perso, principalement parce que ça permet de donner une URL aux gens et ils n'ont besoin de rien installer.
Effectivement on peut faire des trucs jolis avec HTML / CSS / JS et c'est un aspect que j'aime bien. Par contre attention au manque de composants standards, surtout quand on vient d'une boîte à outils comme Qt. On se retrouve vite à réinventer la roue dans chaque nouveau projet, ou devoir embarquer une bibliothèque lourde. Ext.js semble fournir des composants comme pourrait s'attendre quelqu'un qui a fait du Qt. Je n'ai jamais essayé. Ils n'ont pas l'air de surfer sur le modèle du DOM virtuel ou équivalent (faut dire qu'ils sont apparus avant), cher aux dev frontend d'aujourd'hui, mais peut être que quand on n'a pas besoin de recoder le monde entier, c'est moins important.
[^] # Re: un langage pour des petits GUI
Posté par Eh_Dis_Mwan . Évalué à 1.
j'aurai plutôt du écrire "réservé à des élites" (c) (comme la carte super plus premium platinium grossium) https://www.youtube.com/watch?v=OpNHovy8_7c
[^] # Re: un langage pour des petits GUI
Posté par Axioplase ıɥs∀ (site web personnel) . Évalué à 5.
Si je me souviens bien, il y a 20 ans de ça j'utilisais Glade pour faire des GUIs. Grosso modo, tu fais tout joliment dans une UI, et ça génère une config XML. Ensuite, t'as juste à coder ta logique en faisant référence aux identifiants de ta config XML. Un peu comme si tu faisais une app avec AndroidStudio.
Il y a certainement des alternatives pour QT, Swing, etc.
[^] # Re: un langage pour des petits GUI
Posté par _kaos_ . Évalué à 5.
Salut,
Meilleure librairie que j'ai pu voir pour swing : MigLayout.
L'UI, c'est pas mon métier, donc ça traînait mon projet (mais j'avais décidé : rattraper un bout de dette technique).
Et bin ça fait comme échanger une 2 chevaux pour une porche. D'un coup ça va super (trop ?) vite ;)
Matricule 23415
[^] # Re: un langage pour des petits GUI
Posté par steph1978 . Évalué à 3.
J'avais joué avec guietta, en Python+Qt. Plutôt sympa.
[^] # Re: un langage pour des petits GUI
Posté par Goffi (site web personnel, Mastodon) . Évalué à 8.
Python ne manque pas d'outils pour une interface graphique rapide. Ça va de la conversion automatique de la ligne de commande via https://github.com/chriskiehl/Gooey à des outils très complets comme Qt, cf. https://awesome-python.com/#gui-development.
Ça vaut le coup de passer un peu de temps à tester et voir les spécificités selon ce que tu souhaites faire. Depuis quelques années j'utilise Kivy qui n'est pas assez connu à mon avis au regard de ses capacités, avec la possibilité de mélanger du Python avec un langage déclaratif (Kv), et le support pour toutes les plateformes majeures (avec plus ou moins de difficultés pour les plateformes mobiles). J'ai d'ailleurs commencé une dépêche pour présenter tout ça.
Pascal n'est pas cité, mais il y a une communauté très active autour de Free Pascal et Lazarus. Je n'ai pas utilisé moi même, mais j'ai fait du Delphi dans ma jeunesse, c'était vraiment sympa et ça permettait d'avoir des choses concrètes très rapidement. Lazarus a l'air de gérer aussi toute les plateformes principales, et d'avoir une bibliothèque de composants assez fournie. Ça peut être un outil sympa pour faire des choses rapidement.
Une autre option qui sort des sentiers battus, c'est d'utiliser Godot (moteur de jeu libre qui a le vent en poupe), y compris pour faire autre chose que des jeux. C'est un des outils que j'envisage d'utiliser à plus ou moins long terme, parce que je pense que ça peut permettre de faire des choses très rapidement et de manière relativement agréable.
Attention par contre, pour les outils que j'ai cité, l'accessibilité peut être nettement moins bonne que sur des gros acteurs comme Qt ou GTK, c'est à ne surtout pas négliger.
[^] # Re: un langage pour des petits GUI
Posté par Philippe F (site web personnel) . Évalué à 6.
Je rebondis car c'est un point important pour moi: je suis souvent amené à faire des utilitaires avec interface graphique. Du coup, j'ai régulièrement voulu tester ces "nouveaux" langages mais à chaque fois, c'est un gros écueil. Il y a au choix:
- rien
- une pauvre tentative de début de toolkit graphique dont on sent que c'est loin d'être abouti
- un début de binding vers des grosses lib graphiques (Qt, Gtk en général) mais à moitié fini et instable.
Du coup, bin je reste en terrain connu avec mon Python et mon Qt.
[^] # Re: un langage pour des petits GUI
Posté par Selso (site web personnel) . Évalué à 3.
Bonjour,
Il y a un (vieux) sondage sur cette question sur developpez, avec le développement python.
Et malheureusement depuis 2013 le débat est encore ouvert. Je dis malheureusement car finalement ce que l'on reproche à chacune des solutions est toujours d'actualité.
Je ne peux que vous partager un retour d'expérience.
Pourtant python est un bon choix pour du RAD : pas de compilation, mais on peut figer l'application pour le client, beaucoup de possibilité avec ce langage que je ne présenterai pas.
En framework GUI donc :
- PyQt/pyside (binding)
- tkinter
- wxPython (binding)
- pyGTK (binding)
- traitsUI (?)
- kivy (?)
- matplotlib (?)
- DearPyGUI(binding)
Il y en a peut-être d'autres, à voir sur les listes 'awesome' sur github comme celle de vinta pour en citer une.
J'aime bien avoir un designer pour 'présenter' mon interface avant de la coder. Je trouve cela plus efficace.
Bien que le binding Qt soit de plus en plus intégré je suis réticent à embarquer tout un framework avec python. J'ai vu des gens se passer de toute l'API python pour l'usage de thread et String… (attention aussi aux licences Qt)
J'ai essayé tkinter conjointement avec pygubu et je trouve cela bien pour du petit utilitaire pour développeur.
J'ai un client qui a codé toute son IHM avec wxpython, cela lui permet d'intégrer directement les libs de ses scientifiques, tout en présentant une IHM design à son client.
Mon stagiaire a qui j'ai proposé le choix s'est tourné vers pyGTK qu'il a assez facilement pris en main.
Kivy est prometteur, mais distribution pas fiable : impossible à installer sous Windows 10 (désolé).
traitUI et matplotlib répondent à un besoin spécifique de développement, leur force et leur faiblesse donc.
cdlt.
[^] # Re: un langage pour des petits GUI
Posté par FredTux . Évalué à -1.
Bonjour,
PureBasic ! Pour moi c'est un excellent langage simple et très complet !
Je le trouve bien plus simple et rapide que Python par exemple, en plus c'est un langage compilé.
Il y a une aide intégrée très bien faite.
Oui il n'est pas orienté Objet, mais pour moi ça le rend plus simple (chacun son truc).
Contrairement à son nom, sa philosophie se rapproche plus du Pascal que d'un Basic
La version demo est limité à 800 lignes et la version payante coûte 70€
Oui c'est payant, mais c'est développé par une petite entreprise Française
qui a fait un travail incroyable.
Le site : https://www.purebasic.com/french/download.php
Le forum Français : https://www.purebasic.fr/french/
Il y a son pendant pour écrire des WebApplication Spider Basic
https://www.spiderbasic.com/download.php
Mais c'est vrai que ça serait mieux si ce langage n'était pas divisé en deux,
mais a voir dans le futur, peux-être qu'il y aura un jour une fusion. ;)
Un langage qui mériterait d'être open-source et logiciel Libre.
D'avoir sa place dans les plus populaires, pour se faire connaître et grandir, même si ce n'est pas possible car il est commercial et fait vivre ses auteurs.
D'ailleurs, es-que ça serait légal de reprendre sa syntaxe et d'en faire un langage libre ?
Es-que les langages sont déposés ?
# Tcl
Posté par Mackenzie . Évalué à 6.
J'ai utilisé Tcl il y a quelques années et voici ce qui m'avait séduit :
[^] # Re: Tcl
Posté par Corentin Rossignon . Évalué à 6.
J'utilise ce langage tous les jours et il a de très nombreux problèmes :
Et concernant Tk :
Le seul avantage que je trouve à ce langage : le binding C ultra simple
[^] # Re: Tcl
Posté par anaseto . Évalué à 2.
Quel sorte d'application tu développes ?
Sinon, effectivement, Tcl est plus lent que Perl ou Python pour les trucs un peu intensifs.
[^] # Re: Tcl
Posté par Corentin Rossignon . Évalué à 2.
Des simulateurs de satellites, le cœur du programme est en C/C++. Le Tcl est utilisé pour faire l'affichage graphique ainsi que l'exécution de scripts permettant d'interagir avec le simulateur.
[^] # Re: Tcl
Posté par canvas . Évalué à 3.
Un petit truc sympa avec Tcl/Tk c'est qu'il existe une version pour Android (http://www.androwish.org) avec pas mal d'extensions et un SDK.
Cela peut servir à piloter une machine à expresso par exemple.
# Raisons d'essayer Rust
Posté par Colin Pitrat (site web personnel) . Évalué à 10. Dernière modification le 13 novembre 2020 à 20:53.
L'absence de GC n'est pas la seule raison d'essayer (et de préférer) Rust. Personnellement, j'ai tenté le Go et c'est simple avec un bon écosystème. Mais y'a plein de trucs crados fans le design du langage, des librairies et dans l'esprit qui finissent par te rattraper. Avec Rust, j'ai l'impression que beaucoup de choses ont été très bien pensées pour le long terme.
Je pourrais faire une longue liste mais je suis très flemmard alors je donnerai juste un exemple: la gestion d'erreurs. En Rust, tu as Result qui fait que soit tu retournes un résultat, soit une erreur et que l'erreur ne peut pas être ignorée. Tu dois la traiter. Tu peux utiliser unwrap si tu es flemmard, mais au moins tu sais à quoi t'attendre et c'est facile à retrouver.
En Go, le pattern c'est de retourner (resultat, erreur). Si tu ne verifies pas l'erreur, dommage le compilateur ne t'aidera pas à t'en rendre compte. En plus il faut toujours gérer 4 cas: (result, nil), (result, err), (nil, err), (nill, nil). Et si les cas 2 et 4 semble improbables et inutiles, il n'y a pas besoin de chercher très loin dans la doc de la lib standard pour trouver des exemples (read par exemple, qui peut retourner des données et un EOF).
Maintenant j'ai tendance à dégainer Rust pour tout et n'importe quoi. Y'a bien Python qui garde une place dans mon coeur, mais juste pour des trucs rapides, ou pour le plaisir de changer. Et en général avec pytype.
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 7.
Tout à fait, ce que je voulais dire, c'est que ce serait une raison qui me donnerait la motivation additionnelle pour me lancer sans hésitation.
Pour le quatrième, j'ai pas de souvenir d'avoir eu à gérer ça ?
Autrement, il y a pas mal d'outils d'analyse statiques (en plus de go vet) pour Go qui peuvent aider (comme errcheck).
[^] # Re: Raisons d'essayer Rust
Posté par woffer 🐧 . Évalué à 3.
Tu peux utiliser des linters et notamment le metalinter golangci-lint qui fait référence et évitera ce genre d'erreur (entre autres).
Euh, non pas spécialement, si tu retournes la valeur et non son pointeur donc (résultat, erreur) et pas (*résultat, erreur), tu ne peux pas avoir tes deux derniers cas (nil, err) et (nil, nil). Car tu disposeras directement de la valeur qui ne peut être nulle.
Après plus de 6 années d'expérience intensive de programmation en Go, mes fonctions ne retournent pratiquement que des valeurs donc (result,error). Si je dois retourner un pointeur, c'est qu'il y a un besoin bien particulier comme retourner une structure avec un partage d'un espace mémoire (ex : mutex et co).
[^] # Re: Raisons d'essayer Rust
Posté par wilk . Évalué à 2.
Je n'ai jamais compris pourquoi ça n'était pas une obligation (de traiter l'erreur retournée). Ne serait-ce que d'indiquer
_ =
si vraiment on ne veut pas, mais au moins ce serait explicite.Quelqu'un sait la raison ?
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 4.
Go exige d'utiliser une variable définie au moins une fois : ça implique la solution que tu proposes, au détail près qu'il n'y a pas de garantie qu'on n'utilise pas malgré tout la valeur retournée par la suite.
Ce n'est pas évident d'imposer mieux au niveau du langage. En Go les erreurs sont juste une valeur comme les autres, elles ne sont pas traités spécialement par le compilateur ou le langage : il s'agit juste de conventions et d'une interface
error
prédéfinie au même titre que d'autres types prédéfinis (commeint
).La façon classique d'empêcher à 99% (à unwrap ou exception près) d'utiliser une valeur retournée malgré une erreur, c'est les types option et filtrage par motifs qu'on trouve dans les langages avec des types algébriques (OCaml, Rust, etc.).
En Go, on a l'obligation d'utiliser au moins une fois
err
et, ensuite, on peut chercher plus de garanties avec des analyses statiques heuristiques (comme errcheck), indépendantes du langage avec risque de faux positifs et négatifs. En pratique, d'après l'institut de statistiques pifométriques, ça empêche uniquement 98% des problèmes (contre 99% avec OCaml ou Rust), mais permet en échange de conserver un typage simple et de ne pas forcer une imbrication du flot de contrôle. Ce n'est pas un problème facile : en cas d'erreurs imbriquées, l'approche des types option et filtrage par motifs demande, soit du sucre syntaxique ad hoc comme en Rust ou Elixir (comme?
ouwith
qui encouragent à traiter uniquement le chemin où tout se passe bien), soit des concepts avancés comme les monades en Haskell ou des réimplémentions ad hoc de celles-ci. Autrement, ça peut devenir difficile à lire et maladroit.C'est toute la question des avantages et désavantages entre algorithmes de recherche de solution approchée (souvent plus simples et plus rapides au prix de ne pas offrir de garantie absolue) et algorithmes de recherche de solution exacte (plus lents et conduisent souvent à plus de complexité).
Ceci dit, avec les deux approches, rien ne garantie, par contre, que l'erreur est gérée proprement (d'un point de vue sémantique), ce qui arrive plus souvent en pratique et est un problème bien plus difficile qui ne peut être traité par les types que dans les langages avec types dépendants comme Coq.
[^] # Re: Raisons d'essayer Rust
Posté par kantien . Évalué à 2.
Outre le cas de gestion des erreurs en renvoyant un type somme, il me semble étrange qu'un langage moderne ne dispose pas de types sommes. Cela ne rend pas le système de type plus complexe, ni plus dur à implémenter.
Les adeptes des types algébriques ont un slogan qui dit « types as propositions », qui est à mon sens un abus de langage. Un type c'est un concept, mais un concept il faut d'abord le définir et pour cela utiliser une… proposition. Le slogan confond, d'une certaine façon, le défini avec sa définition. Mais, ceci étant, l'absence de type somme fait que l'on ne peut pas écrire de définition disjonctive (type somme) mais seulement des définitions conjonctives (type produit, comme les couples). La disjonction (ou somme) c'est le dual de la conjonction (ou produit) : son absence est difficilement justifiable. Que dirai-t-on d'un langage qui ne fournirait pas l'opérateur
xor
sur un type booléen mais seulement leand
? Il amputerait grandement les capacités d'expression du programmeur.En revanche, il est vrai que la gestion d'un tel type somme pour la gestion des erreurs peut rendre le code plus verbeux sans constructions adéquates dans le langage. Cela oblige à travailler dans une monade et, jusqu'à l'an dernier, c'était assez lourd syntaxiquement en OCaml. Contrairement à Haskell et sa
do
notation, mais je ne sais pas comment s'y prend Rust.D'ailleurs, pour reprendre une partie de ton journal, c'était moins lourd de travailler avec des exceptions que des type option ou result.
Si on prend une fonction de conversion qui renvoie une option au lieu d'une exception cela devient beaucoup plus lourd :
Ou alors, pour être plus générique dans le pattern de code, on utilisera la monade d'option (ce qui complique grandement la charge cognitive pour le programmeur).
Heureusement, depuis un an, on peut écrire un code moins abscons et plus proche de la version avec exception, mais c'est très récent.
N'ayant jamais utiliser Rust, on doit s'y prendre comment pour travailler dans une telle monade ?
Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 2.
Pour ce qui est des types somme en soi, ce n'est effectivement pas compliqué à implémenter : en fait, les interfaces de Go (qui sont des valeurs) peuvent être (et au besoin sont) utilisées exactement comme les types somme à l'aide d'un type switch (le cas courant de l'énumération se fait d'habitude avec des constantes). La seule différence, c'est que le nombre de types qui peuvent implémenter une interface n'est pas limité, contrairement aux types somme, ce qui veut dire qu'on ne peut pas faire de vérification d'exhaustivité. Une façon d'implémenter les type somme en Go sans introduire un concept trop différent, ce serait une façon de spécifier une liste fixe de types implémentant une interface explicitement (les interfaces sont implémentées implicitement autrement). Pour le moment, on dirait qu'ils n'ont pas considéré le bénéfice (check d'exhaustivité) suffisant pour introduire un nouveau concept, même s'il n'y a pas non plus d'opposition claire.
Pour le coup, les exceptions peuvent conduire à du code concis, oui, sauf que c'est la méthode la moins explicite, invisible dans les signatures de fonction en OCaml, et offrant les bugs les plus inattendus.
J'ai pas vu passer ça ! J'imagine que c'est une extension ppx, ou alors directement intégré dans le langage ? Est-ce que ça couvre le cas des erreurs, idéalement avec une façon permettant de l'annoter ?
En Rust, ils se sont contentés de sucre syntaxique à l'aide d'une macro
?
spécifique au cas du type option pour une erreur (type Result). C'est possiblement un bon compromis, surtout qu'ils ont fait l'effort de trouver une solution pour les annotations simples d'erreur (implémenter un trait de contexte pour Result).[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 2.
Un truc intéressant : il existe un outil d'analyse statique qui vérifie l'exhaustivité pour des types choisis sur la base d'annotations en commentaire. J'imagine que ça peut parfois valoir le coup, même si c'est un peu verbeux.
[^] # Re: Raisons d'essayer Rust
Posté par kantien . Évalué à 2.
Cela peut certes être utilisé dans certain cas en lieu et place d'un type somme, mais ce n'est vraiment pas la même notion. Les interfaces, c'est les type classes de Haskell ou les traits de Rust, mais en version du pauvre. Les fonctions qui prennent un interface en paramètre c'est juste des fonctions qui prennent un paramètre implicite qui est de type produit.
Par exemple, un type que l'on peut convertir en chaîne de caractères, on pourrait l'écrire comme cela en OCaml :
Ce que font les interfaces de Go, les types classes ou les traits c'est instancier implicitement le dictionnaire de méthodes en fonction du type du paramètre
value
. De telle sorte qu'il suffit d'écrireprint 1
au lieu deprint {show = string_of_int} 1
. Mais un dictionnaire, cela reste un type produit. C'est surtout utilisé pour faire du polymorphisme ad hoc, et non pour se substituer au type somme.Pour faire la même chose en OCaml, avec la même généralité que les type classes de Haskell, il faudrait passer par le système des modules et foncteurs. Un module est un dictionnaire (type produit), qu'il faudrait passer comme argument implicite à une fonction. Il faut pour cela étendre le système des modules de première classes (en faire des valeurs comme les autres), puis ajouter un système de résolution pour arguments implicites. C'est un objet de recherche en cours.
C'est du sucre syntaxique intégré au langage depuis la version 4.08, mais c'est inspiré de ce qui se faisait avant avec des extensions ppx. Cela a été fait pour simplifier le code qui utilise des monades ou des foncteurs applicatifs (cf. la doc sur les binding operators). Je trouve que cela rend mieux compte du choix du nom
bind
pour l'opérateur monadique que ne le fait lado
notation de Haskell. Le>>=
c'est juste une généralisation du pipe du shell qui est lebind
de la monade identité.Le code avec les exceptions j'aurais pu l'écrire ainsi si j'avais utilisé le pipe :
ou avec la type classe de la monade identité :
Ce qui est le même code que la version monadique avec le type option. Réciproquement, le sucre syntaxique des binding operators permet de récupérer la forme non monadique pour du code monadique.
Comme OCaml maintenant, si je comprends bien.
Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 2.
Non, pas vraiment : en Go les interfaces sont des valeurs à part entière assimilables à un couple
(type, valeur)
dont on peut inspecter chaque composant à l'exécution. L'application de méthodes permet d'en faire une utilisation en tant que type produit (instatiation implicite du dictionnaire des méthodes), mais un switch sur le type (non effacé par la compilation, contrairement aux types classes ou traits) permet d'en faire une utilisation en tant que type somme.C'est bien une notion à cheval entre les deux, qui regroupe des applications des types somme (par exemple pour représenter un ast) et types classes/traits (utilisation type produit) sous une même notion. Elle ne va pas aussi loin sur aucun des deux aspects (type somme et produit) et est un peu plus verbeuse dans son utilisation type somme, mais elle a le mérite de traiter les deux à l'aide d'un seul concept. Enfin, en bonus, elle résout aussi la question de la réflection et ses applications intéressantes (en particulier en sérialisation) dont on ne profite ni en Rust, ni en OCaml ou Haskell.
[^] # Re: Raisons d'essayer Rust
Posté par kantien . Évalué à 1. Dernière modification le 16 novembre 2020 à 18:26.
C'est l'implémentation de la fonctionnalité qui veut cela, mais ça n'a rien à voir avec la notion générale de type somme. La valeur (du couple) est un dictionnaire, c'est-à-dire un type produit. Quand vous utilisez une interface, vous affirmez l'existence unique d'un certain dictionnaire pour le type qui vous intéresse. Alors, effectivement, un énoncé qui quantifie existentiellement et de manière unique sur les types est équivalent à une disjonction exclusive infinie, mais c'est là une vision tordue de ce que sont réellement les types sommes.
Quand on dit qu'il existe un unique entier satisfaisant une propriété P, c'est tout comme si l'on disait cette disjonction exclusive infinie : P0 ou P1 ou P2 ou P3… Avec vos interfaces vous fait la même chose mais en quantifiant sur les types, puis vous examiner au runtime lequel des types implémente le dictionnaire. Mais c'est là un choix d'implémentation du mécanisme (c'est bien plus simple que de tout gérer à la compilation) qui dans le principe n'est rien d'autre que celui des arguments implicites de type produit. Vous auriez pu faire la même chose en vous contentant d'avoir une représentation du type au runtime et sans interface.
C'est tout à fait possible en OCaml avec les types GADT extensibles, mais je dois dire que je n'en ai jamais bien compris l'intérêt (c'est quoi ces fameuses applications intéressantes ?). À la différence qu'il faut se taper à la main ce que le compilateur Go fait automatiquement pour vous. Un GADT extensible permet de définir une somme illimitée de couple (type, valeur), ce qui est l'implémentation retenue pour les interfaces.
Exemples avec mon interface
showable
:Voilà, ma valeur
couple
est une paire constituée d'une représentation au runtime du typeint
ainsi que d'un dictionnaire implémentant l'interfaceshowable
pour lui. Mais avec les type sommes extensibles, on perd la vérifications de l'exhaustivité lorsque l'on s'en sert. ;-)Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 4. Dernière modification le 16 novembre 2020 à 21:25.
C'est peut-être une vision tordue (pour le théoricien du typage), mais, dans les faits, c'est équivalent (au côté infini près) et simple à comprendre, même si ce n'est pas une implémentation exclusive des types somme directement calquée sur un papier de recherche. Et ce n'est pas une question d'implémentation : le langage définit explicitement ces actions pour les interfaces, donc ça fait partie du langage (beaucoup de code en dépend).
Par exemple, en Go on peut faire sans plus d'histoires un marshall et unmarshall (à l'aide du module encoding/gob) de presque n'importe quel type de façon type safe (en OCaml le module équivalent n'est pas type safe). Autre exemple : printf.
Ce n'est pas une petite différence ! Surtout que le « à la main » passe par le concept de GADT, qui n'est pas le plus accessible, et je ne vois pas comment tu pourrais définir une fonction qui marche pour tout type (dont ceux définis ultérieurement par un utilisateur).
Note que, bien que pratique, la vérification d'exhaustivité a un inconvénient : elle ne se prête pas aux modifications et réparations graduelles du code. Si tu ajoutes un habitant à ton type somme, tu casses toutes les utilisations. Inversement, si on essaie de changer les utilisations d'abord, l'exhaustivité empêche de compiler également. C'est pas forcément toujours important, mais ça se heurte à certaines façons de faire : par exemple, faire son refactoring à base de petits commits, sans casser le code entre-temps.
[^] # Re: Raisons d'essayer Rust
Posté par kantien . Évalué à 1. Dernière modification le 17 novembre 2020 à 01:42.
Pas besoin d'un papier de recherche pour cela, la notion de type somme c'est du niveau licence en mathématiques : c'est la somme disjointe d'ensemble (définie par une disjonction exclusive) qui est la notion jumelle du produit cartésien (type produit défini par une conjonction). Il n'y a rien de hautement sophistiqué là-dedans. C'est bien pour cela que je m'étonne de leur absence.
D'ailleurs, outre cette représentation dynamique des types, vous avez d'autres types sommes dans le langage. Si j'ai bien compris, la valeur
nil
peut être affectée à n'importe quel type, ce qui fait qu'en réalité vous ne manipulez que des types options, qui est un type somme : c'est le type1 + A
pour tout typeA
. Ce qui fait que lorsque vous avez des fonctions qui peuvent retourner une erreur, en renvoyant une paire, vous retournez un type produit de la forme suivante :(1 + A) * (1 + B) = 1 + A + B + A*B
, où l'on voit les 4 cas à gérer que déplorait Colin Pitrat dans son premier commentaire. Là où, avec un type somme de résultat, il n'y a que les deux casA + B
.Et ce n'est pas équivalent, même dans les faits. Cela l'est tout autant que Platon définissant l'homme comme un bipède sans plumes, et Diogène le cynique de le rayer en se promenant avec un poulet déplumé tout en haranguant la foule d'un « Voici un homme ! ».
Il y a d'autres types sommes infinis que l'on ne peut définir, en tant que tel, avec Go : celui des listes par exemples. Un type somme récursif, comme celui des listes, se développe en une somme infinie :
1 + A + A^2 + A^3 + ...
, c'est-à-dire la liste vide, ou les listes à un élément, ou les listes à deux éléments, ou les listes à trois éléments…Tout ce que vous avez, c'est le type somme extensible que j'ai défini précédemment, qui est géré par le compilo et accolé dans une paire à toute valeur utilisant une interface. Puis vous faites du pattern matching dessus. Mais les seuls cas d'usage que j'ai vu, c'est avec l'interface vide pour palier le manque de polymorphisme dans le langage. L'exemple que tu m'as donné pour les arbres ne semble pas faire de d'analyse de cas sur la représentation dynamique des types, mais définir des arbres dans un langage qui n'a pas de type somme (directement définissables et accessibles au programmeur) mais que des types produits (ou struct ou enregistrements…) comme on peut le faire en C, C++, Java, Python, etc.
Ce que je veux dire c'est que l'outillage est là pour avoir une représentation dynamique des types, et que ce que j'ai fait à la main le compilo pourrait le faire automatiquement. Ce n'est pas la partie la plus dure, seulement je ne crois pas que quelqu'un y ait vu un quelconque intérêt à l'implémenter.
Je ne vois pas comment tu pourrais le faire aussi, simplement en bénéficiant d'un représentation dynamique des types. Soit la fonction est polymorphiquement paramétrique et là c'est très usuel en OCaml, soit le poylmorphisme est ad hoc et c'est le système des type classes (ou interface pour Go, mais le switch sur type ne sert à rien). Où a-t-on besoin d'une représentation dynamique des types ?
On peut faire de la sérialisation/déserialisation de manière type safe en OCaml, mais c'est ad hoc, il faut choisir son format. Les modules de la lib standard font cela de manière générique, ce qui ne peut être type safe. Même si l'on avait une représenation dynamique des types, je ne suis pas certain que l'on puisse réellement faire cela de manière générique et type safe.
Pour faire un
printf
type safe il me semble qu'il faut les types dépendants, et en OCaml c'est implémenté via un GADT.Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
[^] # Re: Raisons d'essayer Rust
Posté par Nicolas Boulay (site web personnel) . Évalué à 5.
En Go, les valeurs ne prennent pas nil, seulement les références.
"La première sécurité est la liberté"
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 3.
C'est pas étonnant qu'ils soient absents, puisque la pratique de programmation qu'ils couvrent est déjà couverte par le concept des interfaces (bien que ce ne soient pas des type somme implémentés de façon scolaire). Je donne un exemple plus bas pour les listes simplement chaînées.
Uniquement à un type pointeur
*A
(équivalent àoption A
), et il n'y a pas une seule valeur nil, mais une différente pour chaque type pointeur (A(nil) est différent de B(nil)). Et c'est en effet un type somme qui couvre le cas courant du type option.Sauf que les conventions font qu'il n'y a pas 4 cas en pratique, mais bien 2 sauf 3 dans de rares cas comme Read qui peut renvoyer une erreur EOF qu'on peut vouloir traiter de façon particulière (cas non gérable par un simple type somme A + B de toutes façons).
Eh bien si, mais le fichier que j'ai donné contient uniquement la définition, pour les utilisations il faut regarder ailleurs comme ici qui implémente une marche sur l'ast en faisant un switch sur le type de l'interface qui sert à représenter un nœud.
Si on peut définir un ast, on peut définir en particulier une liste simplement chaînée :
Ici j'ai défini un type pour les listes d'entiers : jusqu'à ce qu'on ait des types génériques en Go (dans un an ou deux), si on veut plus générique il faut utiliser
interface{}
à la place deint
, ce qui donne des listes non limitées à un seul type, comme dans Python, Perl ou Lisp.En pratique je sais pas si grand monde fait ceci, vu que les listes simplement chaînées n'apportent que rarement quelque chose par rapport à un tableau dynamique.
Ah si, en Go c'est bien type safe : lorsque la valeur marshallée n'est plus compatible (parce que le code a évolué, par exemple, ou qu'on essaye de la récupérer dans le mauvais type), on obtient proprement une erreur.
Les types switchs sur les interfaces combinés au package reflect permettent d'inspecter les types (par exemples récupérer une liste des champs d'un struct). On peut donc définir printf récursivement sur une interface : les feuilles correspondent aux types de bases du langage (
int
,float64
, etc.). Un exemple accessible est la définition récursive de Printf pour des types quelconques : ici on a un switch sur les types simples et un traitement différent pour les types plus complexes de typereflect.Value
dans une fonction différent ici (en particulier la gestion récursives des structs, maps et tableaux).Pour Printf en Go ce que je veux dire c'est qu'il peut afficher n'importe quel type de façon générique (le type est passé sous la forme interface{} pour pouvoir l'inspecter), même ceux définis par un utilisateur : pratique pour debugger par exemple. En OCaml il faut définir un affichage pour chaque type. En Haskell et Rust c'est pareil (aux derive près qui rendent la chose un peu plus facile, mais cela reste très manuel).
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 2. Dernière modification le 17 novembre 2020 à 11:03.
Petit détail : à la place de
j'aurais du écrire :
puis utiliser
l
et pasmylist
dans le Printf (ça change rien au résultat ici, mais sinon je n'illustre pas vraiment un type switch sur une interface dont on ne connaîtrait pas le type concret).[^] # Re: Raisons d'essayer Rust
Posté par kantien . Évalué à 2. Dernière modification le 17 novembre 2020 à 16:32.
Absolument pas, et ton exemple sur les listes chaînées me le prouvent une fois de plus. Mais là on tourne en rond, et tu ne sembles vraiment pas saisir à quoi servent les type sommes (étonnant pour une personne ayant programmé en Rust, Haskell, OCaml et Coq).
Avec les types sommes ce serait plus qu'une convention, elle serait vérifiée statiquement par le type checker. Outre l'API étrange de renvoyer une erreur et une résultat en même temps, cela se fait très bien avec un type somme, même de la forme A + B. L'existence du troisième cas fait que la valeur de retour est de la forme
A + B + A * B
, ce qui, par de l'algèbre niveau collège, se ramène à une somme de deux termesA + B * (1 + A)
Pour le reste c'est lié à la réflection et au typage dynamique du langage, ce qui peut aussi se faire statiquement à base de prépocesseur comme en Haskell, Rust… ou OCaml. Et donc toute cette discussion est hors sujet par rapport à l'existence ou l'absence des types sommes.
Soit dit en passant, si l'on oublie de traiter un cas dans un type somme, le code compile et le compilateur émet un warning et non une erreur :
Autrement dit cela fait exactement ce que tu attends (cf. une de tes réponses à Nicolas Boulay)
C'est exactement le comportement du compilateur face aux types sommes : warning et analyse statique.
Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 2.
Mon impression, c'est que tu ne sembles pas saisir les subtilités des interfaces Go partant de préjugés sur le sens du mot « interface » et de comment sont implémentées certaines choses (comme la réflection) dans d'autres langages : bien que servant pour le dispatch dynamique de méthode (typage produit), ainsi que pour la réflection, elles sont des valeurs typés statiquement et les type switchs qui permettent d'accéder au type concret sont typés 100% statiquement également. Même concernant le check d'exhaustivité, rien n'empêcherait de le faire non plus (comme le prouve l'existence d'une analyse statique dont j'ai donné le lien).
Comme tu le dis, ayant programmé dans ces quatre langages, je pense savoir ce qui est possible ou non avec un type somme et, en dehors des limites du fait de l'absence de généricité en Go, je peux représenter tout type somme comme la disjonction des types satisfaisant une interface.
Lors d'un type switch il n'y a pas de typage dynamique : toutes les variables sont typés statiquement dans chaque branche, comme lors d'un filtrage par motif d'un type somme. En Go, il n'y a une sorte de typage dynamique uniquement lors des assertions de type explicites, mais pour le coup c'est vraiment une question orthogonale (même si elles partagent une partie d'implémentation et concepts par simple économie d'ingénierie).
Et « le reste » c'était pour répondre à ta question annexe des applications intéressantes de la réflection et choses qu'elle peut faire et que Rust, Haskell ou OCaml ne peuvent pas faire (le préprocesseur sert uniquement à réduire la quantité de boilerplate, mais ne résout pas le problème de fond). L'utilisation de Printf dans l'exemple que j'ai donné l'illustre bien : rien n'a été fait pour permettre l'affichage des nouveaux types.
Pour le coup, my bad, ça fait un moment que je fais pas d'OCaml, j'ai dû confondre avec Rust où cela produit bien une erreur et non un warning.
[^] # Re: Raisons d'essayer Rust
Posté par kantien . Évalué à 2. Dernière modification le 17 novembre 2020 à 23:59.
C'est pas un préjugé sur le mot « interface », c'est ainsi que le concept est présenté dans A Tour of Go.
Et je dois dire que j'ai toujours du mal à voir en quoi, avec tous les exemples que tu me donnes, cela peut être considérer comme fournissant une fonctionnalité équivalente aux types sommes. Si c'est le cas tu dois bien pouvoir me définir simplement la somme de deux types, disons
int
etstring
, de telles sortes que le type ainsi défini ne puisse contenir que des valeurs de l'un ou de l'autre (union ensembliste) et rien que celles-là.Autrement dit, tu dois pouvoir me définir cela (je l'espère sans encodage tricky) :
À partir de ton type de liste de int, tu devrais pouvoir définir trivialement cette version de la fonction
last
calculant le dernier élément de la liste :Quand je dis cette version, c'est celle avec 5 switchs. C'est équivalent au déroulement d'une boucle. Partant du type
list A = 1 + A + A^2 + A^3 + A^4 +...
, j'ai un switch pour les puissances 0, 1, 2 et 3 puis un dernier pour toute puissance ≥ 4.Comme peux tu limiter, à priori, les membres de cette disjonction ? Qui te dit qu'un utilisateur, sur lequel tu n'as aucun contrôle, ne créera pas un type satisfaisant l'interface en question ?
Tant que je n'aurais pas une solution, claire et nette, à ces problèmes, je ne considérerais pas les interfaces comme un substitut aux types sommes. Même pas de loin, en tant que version du pauvre.
Quand je parlais de typage dynamique, je faisais allusion au type
interface{}
. C'est le typetop
(celui qui contient tout valeur, qui est le plus grand de tous les types par la relation de sous-typage), et un type switch sur une telle valeur ressemble fortement à du rafinement de type dynamique (même si le type est connu statiquement dans chaque branche). Un langage à typage dynamique, comme Python, est un langage avec un seul type statique à savoirtop
. C'était pour parler de votre gestion duPrintf
, qui est appelé sur cette interface.Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 3.
Oui, enfin, c'est un tutoriel. Notre échange ne porte pas, j'espère, sur l'application la plus commune des interfaces Go (auquel cas on serait d'accord que les types somme n'est pas cette application), mais sur leur expressivité d'un point de vue typage.
C'est possible d'exprimer cela à l'aide du système de types. Tu peux considérer cela tricky, si tu veux, je ne vais pas débattre sur ce genre de considérations : l'encodage demande simplement l'écriture d'une méthode vide pour affirmer que le type satisfait l'interface, donc deux fois plus verbeux qu'avec un type somme dédié.
Là tu parles d'autre chose : tu parles de l'expressivité de la construction de filtrage par motif et de sa destructuration en profondeur qui est plus du domaine de la syntaxe (le genre de trucs qui s'implémente avec des macros en lisp ou racket). En Go, tu n'as pas de syntaxe facilitant cela. Comprenons-nous bien, c'est bien une fonctionnalité syntaxique liée aux type sommes, mais ce que tu semblais débattre c'était la fonctionnalité de typage, la possibilité même de représenter les types somme à l'aide du système de types !
C'est une question valable : en Go tu pourrais rajouter des habitants en code utilisateur, mais ça n'affecterait que le code de l'utilisateur pour une éventuelle analyse statique d'exhaustivité, ça ne va rien casser; une façon d'éviter cela pour un utilisateur, c'est de ne pas exporter la méthode publiquement; en pratique, l'utilisateur ne va pas implémenter une méthode pour satisfaire l'interface de toutes façons.
Je ne vais pas débattre de la notion de version du pauvre : perso je parle uniquement sur ce qu'il est possible ou non d'exprimer avec le système de types de façon pas trop compliquée.
Personnellement, ma définition de langage dynamique est différente (à ce titre Perl n'est pas à typage dynamique, car sans type top unique), d'où ma confusion, mais admettons. Un type top semble nécessaire pour définir un Printf avec de la réflexion (que ce soit avec du typage statique ou dynamique).
[^] # Re: Raisons d'essayer Rust
Posté par kantien . Évalué à 2.
Je vais plutôt donner un réponse générale à ton commentaire qui, malheureusement, confirme ma position initiale : le système des interfaces n'est pas une alternative viable aux types sommes.
Premièrement, ta solution d'interface
IntOrString
ne répond pas pleinement au problème. La somme est ouverte et non fermée, j'ai pu y rajouter unfloat64
avec ce code :Le point positif, si on passe un valeur de type C à une fonction qui attend uniquement un A ou un B, est que tout se passe bien. J'ai testé avec une fonction d'affichage (qui alors n'affiche rien), mais si elle devait retourner une valeur je suppose qu'elle retournerait la valeur par défaut de son type de retour (il me semble que chaque type a une valeur par défaut).
Néanmoins, le filtrage par motif n'est pas qu'une affaire de syntaxe : c'est un élément crucial dans l'utilisation des types sommes, sans cela ils perdent tout de leur intérêt. Mon point n'était pas tant de savoir si l'on pouvait encoder des types sommes avec les interfaces, mais de savoir s'ils satisfont cette requête :
J'ai cité un extrait d'un de tes commentaires précédents. Sans le filtrage par motifs, ils ne couvrent absolument par la pratique de programmation des types sommes. En revanche, sous le capot, ils sont bien implémentés sous la forme d'un type somme extensible, comme celui que j'avais utilisé pour la réflexion. C'est là un choix d'implémentation pour la fonctionnalité du polymorphisme ad hoc.
Il y a eu deux propositions pour ajouter cette fonctionnalité à OCaml : une basée sur une implémentation à la Go utilisant le type pour la réflexion et une autre basée sur le système de modules et foncteurs à la type classes de Haskell. C'est la dernière qui a était retenue et qui est en cours d'élaboration, mais qui demande encore des travaux de recherches pour faire cela proprement au niveau du système de types.
Quoi qu'il en soit, merci pour cette échange qui m'a permis de comprendre un peu mieux la manière dont les interfaces sont implémentées dans ce langage.
Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 4.
Oui, tout à fait.
Oui.
Il n'y a pas de filtrage par motif avec patterns qui vont au-delà d'un niveau de profondeur de destructuration (l'équivalent du type switch), donc il faut imbriquer des type switchs au besoin pour plus de profondeur.
Au final, c'est de mon point de vue bien une différence syntaxique, même si récursive (implémentable par macro récursive, mais macro quand même). De là à dire qu'ils perdent tout de leur intérêt et que c'est non viable, je suis un peu surpris. D'après mon expérience, les destructurations à juste un niveau de profondeur sont les plus fréquentes. La plupart des filtrages par motifs se traduisent en un seul type switch, parfois une imbrication dans certaines branches, ce qui reste dans le domaine du viable à mon avis. Je me demande quels types d'applications tu as en tête, pour que le côté récursif en profondeur de la destructuration te semble à ce point indispensable.
Merci aussi, c'était intéressant d'avoir le point de vue de quelqu'un qui découvre Go avec un état d'esprit venant de OCaml. Ça m'a permis de me mettre à jour sur certaines nouveautés en OCaml !
[^] # Re: Raisons d'essayer Rust
Posté par kantien . Évalué à 2. Dernière modification le 18 novembre 2020 à 17:46.
Regarde par exemple ce fil de discussion ouvert par Gasche sur le forum OCaml : Musings on extended pattern-matching syntaxes. Tu verras à quel point le pattern matching est essentiel dans l'utilisation poussée des types sommes. Quand on a des types sommes un peu partout, on déstructure à tous les niveaux et tout le temps.
Je t'accorde que la différence est syntaxique, et ne concerne pas le système de types, mais elle est essentielle pour l'usage convenable de types sommes. Déjà qu'ils sont une plaie à définir en Go, qu'ils sont ouverts et non fermés, si en plus on n'a aucune construction syntaxique aidant à leur usage, ce qui est clair et net c'est que ce n'est absolument pas une alternative viable aux types sommes.
Quand je t'ai montré comment faire de la réflexion avec des GADT en OCaml, tu m'as répondu cela :
Et après tu me présentes les interfaces comme alternatives crédibles aux types sommes, via ton encodage du dessus. Tu es à la limite de la mauvaise foi sur le coup.
Je veux bien t'accorder que le concept de GADT, si on veut en explorer tout le potentiel, est difficile d'accès. Mais le cas d'usage que je proposais est utilisable par n'importe qui, sans avoir besoin de saisir les subtilités qu'il y a derrière. Je redonne sa définition :
Sans rien comprendre à ce qui passe derrière, lorsque l'on définit un nouveau type, disons celui-ci :
il suffit de faire avec :
c'est-à-dire rajouter un constructeur constant qui à le nom du type puis lui donné le bon type. Ce n'est certainement pas plus compliqué que ton encodage de types somme ouverts. Et au fond, votre type
interface {}
ce n'est rien d'autre que celui-ci emballé dans un type existentiel :Exemple de code qui prend une interface {} et fait un switch sur type :
Ce qui revient à ce que je disais depuis le début : vous avez un type somme extensible gérer par le compilateur pour chaque interface, qu'il enveloppe dans une type existentiel. Comme je l'ai fait : j'ai emballé le GADT extensible dans un couple (type, valeur) puis je fait du pattern matching sur des constantes : ce à quoi se résume ton encodage des types sommes en Go.
Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 4.
J'ai lu le fil de discussion, et je suis honnêtement un peu dans la même situation que schonfeder à la fin : je suis assez perplexe quand au problème pratique que résolvent ces considérations syntaxiques, il me manque un contexte. Là, on a affaire à une discussion à propos d'une syntaxe qui n'existe que dans une extension expérimentale, sans indications du problème qu'elles rendraient significativement plus simple en pratique : c'est une réponse à cela que je cherchais avec ma question.
Peut-être suis-je biaisé dans mon expérience en OCaml et Coq. C'est surtout Compcert et lecture de quelques parties du compilateur OCaml : l'essentiel des filtrages par motif qu'on y trouve ne fait pas appel à des fonctionnalités avancées ni à des destructuration vraiment profondes, c'est du code plutôt simple, assez verbeux et accessible (peut-être la partie (f)lambda plus nouvelle fait-elle un usage plus avancé du filtrage par motif ?).
Je t'accorde cela. Note cependant que l'idée qu'il est possible pour un programmeur OCaml d'écrire du code inacessible à d'autres programmeurs OCaml ne passe pas bien dans toutes les communautés. Go est un peu une réaction en ce sens : l'idée que tout programmeur doit être capable de maîtriser le langage grosso-modo dans son ensemble, pour faciliter les contributions externes ici et là. C'est pour cela que j'ai écrit :
Car la possibilité de faire accepter une feature comme les GADTs dans la communauté Go est nulle, même si une de leurs applications est relativement accessible.
Et puis tu compares un différence de verbosité (encodage verbeux des types somme en Go), voire d'expressivité du typage (distinction somme ouverte ou fermée conduisant à des warnings utiles), à une différence d'expressivité du langage (définir une fonction d'affichage qui donnera un affichage par défaut pour les types créés par n'importe quel utilisateur). Qu'est-ce qui est plus ou moins important restera subjectif, mais il s'agit de considérations de nature différentes quand même.
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 4.
J'ai lu un peu les pages suivantes : l'exemple de trefis est intéressant et montre une différence plus significative (un seul
raise
au lieu de trois), au prix d'une formule un peu longue.Ceci dit la version proposée utilisant les types somme actuels :
ressemblerait beaucoup à la version Go naturelle :
qui, dans ce cas particulier pourrait être raccourcie (mais c'est pas idiomatique) :
dans le même style que la solution proposée avec la nouvelle syntaxe qui fonce direct sur la seul cas intéressant :
Mais, est-ce une situation fréquente que de se retrouver avec seulement un cas qui correspond à un résultat, et tout plein de cas qui correspondent exactement à la même erreur ? Et si on veut ajouter un contexte à l'erreur au lieu d'un simple Not_found (est-ce que c'est h ou g qui n'a pas trouvé de résultat ?), la nouvelle syntaxe proposée n'est plus utilisable.
[^] # Re: Raisons d'essayer Rust
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
Que pensez-vous de la futur généricité dans Go ?
cf https://blog.golang.org/generics-next-step
Est-ce que cela se rapproche des modules paramétriques OCaml ou pas du tout ?
"La première sécurité est la liberté"
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 4.
C'est beaucoup moins puissant, mais aussi beaucoup moins compliqué (tant pour l'utilisateur que l'implémentation). Mais faut dire que les modules paramétriques OCaml sont vraiment puissants par rapport à ce qu'on trouve ailleurs.
Dans les différences concrètes que je peux voir se produire en pratique, il n'est par exemple pas possible d'utiliser une fonction générique autrement que pour l'instantier ou l'appeler (donc, si j'ai bien compris le draft, tu ne pourras pas faire une fonction qui renvoie une fonction générique, par exemple). On peut aussi uniquement paramétrer par des types et non des valeurs. Pas de généricité dans les paramètres de méthode non plus (la question de savoir si une méthode permet de satisfaire une interface deviendrait floue).
J'aimais pas trop certains drafts précédents, mais le dernier je le trouve pas mal : faudra voir ce que ça donne et couvre statistiquement en pratique.
[^] # Re: Raisons d'essayer Rust
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
En C++, l'explosion de code provenait de la création d'une nouvelle fonction à chaque usage d'une fonction générique. Les compilo essaient tant bien que mal de factoriser tout ça,mais ce n'était qu'une optimisation.
J'aimais bien le concept de créer un type réel à partir d'un type générique en Ocaml, cela permet justement d'éviter de créer "sous le tapis", une nouvelle fonction.
Je ne sais pas comment Go va gérer ça.
"La première sécurité est la liberté"
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 3.
A priori les fonctions génériques seront compilées une seule fois :
J'imagine que définir les contraintes pour les types génériques à l'aide d'interfaces rend cette approche assez naturelle. Rien dans le draft n'impose vraiment une approche ou l'autre, ceci dit.
[^] # Re: Raisons d'essayer Rust
Posté par kantien . Évalué à 3.
Ça c'est parce que C++ pratique la monomorphisation afin de spécifier chaque instance de template et avoir un code plus efficace. Cela se fait au prix d'une multiplication du nombre de fonctions pour chaque instance d'une template. C'est un choix de stratégie de compilation : les template sont instanciés à la compilation, là où un foncteur OCaml ne génère qu'une fonction et est instancié à l'exécution (une fois compilé un module n'est rien d'autre qu'un enregistrement comme les autres, tous les types étant effacés à la compilation, et un foncteur un fonction générique qui crée un enregistrement à partir d'un autre enregistrement).
Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
[^] # Re: Raisons d'essayer Rust
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
Quand tu as 10 fois totot() dans le code, dupliqué 10 fois le code n'est plus rapide que dans un microbenchmark. L'inflation de la taille de code ne permet pas d'utiliser le cache Instruction correctement. Il est plus efficace d'avoir une fois le code et gérer l'inline au besoin (selon que toto<>(a) est petit ou gros, ou si "a" est une constante).
"La première sécurité est la liberté"
[^] # Re: Raisons d'essayer Rust
Posté par kantien . Évalué à 1. Dernière modification le 19 novembre 2020 à 16:20.
Je peux comprendre que tu ne perçoives pas l'intérêt de la proposition expérimentale de gasche, mais le but du lien était de te montrer que les power users des types somme ressentent le besoin de travailler sur les patterns et motifs de destruction, que cela fait partie intégrante de l'usage des types sommes. Un type somme ne peut s'utiliser autrement que par déstructuration de son motif.
Si tu veux un exemple moins alambiqué et bien plus courant, regarde celui de la fonction
simplify_first_col
dans ce journal de gasche. Ou celui-ci :Quand on fait une somme de somme, extrêmement courant dans un langage disposant nativement et naturellement de types somme, on aime bien aplatir la somme dans la destruction de motif.
Alors premièrement la distinction somme ouverte ou fermée est de la plus haute importance ! Cela va bien au-delà de l'existence de warnings utiles, il s'agit de savoir de quoi l'on parle. Une somme ouverte est plus ou moins improprement appelé une somme. Elle ne désigne pas un seul type précis mais une famille illimitée de types : faire passer l'un pour l'autre s'est se moquer du monde. Je me souviens d'avoir vu reprocher en ces lieux que les philosophes ne définissaient pas ou mal leurs concepts, ce qui m'avait fait sourire, mais à côté des programmeurs ils sont la rigueur incarnée en comparaison.
Une somme de deux types c'est le plus petit des majorants (à isomorphisme près) par la relation de sous-typage, une somme ouverte les contenant c'est un majorant quelconque ! Je te donne deux entiers, disons 2 et 3, et si je te dis que 36 est leur plus petit commun multiple tu ne tiques pas ? C'est exactement ce que tu fais en voulant éluder la distinction entre somme ouverte et fermée. Le produit étant la version duale c'est à dire les plus grand des minorants, ou le pgcd pour l'analogue chez les entiers.
Donc non, c'est clair, vous n'avez pas la somme de deux types en Go, jusqu'à preuve du contraire. Ou si vous l'aviez, il faudra m'expliquer la raison étrange d'avoir choisi le produit, et non la somme, comme convention pour vos fonctions pouvant retourner une erreur (ce qui est le point de départ de toute cette discussion).
Je le répète et j'insiste profondément : tu n'as pas encodé la somme de deux types. Ce point là, je ne te l'accorderais jamais. Par comparaison, on mimique en OCaml avec des types fantomes ce qui en réalité relève des types dépendants : le concept de fichier en lecture seul est un type dépendant. Et pourtant aucun développeur OCaml n'irait soutenir que l'on a des types dépendants en OCaml (voir cette interview de Leo White).
Ensuite mon illustration sur le type
top
et la fonction qui en fait usage avait pour but de t'expliquer, avec du code, ce que gasche t'avait déjà expliqué en 2017. Et pour ceux de ta communauté (voir la PR sur les type somme) qui craignent un problème d'interaction entre type somme etinterface {}
, ils ne se passe rien, tout va bien :Pour ce qui est de la fonction d'affichage générique, c'est une question de goût : je n'en ai rien à faire. Pour être franc et honnête, le système de types de Go est pour moi de l'ordre du jouer playskool que l'on donne aux enfants, je n'irais pas utiliser une telle chose juste pour disposer d'une telle fonction : j'ai des ppx pour cela, elles dérivent un formateur pour les types définis par l'utilisateur et utilisables avec la chaîne de formatage "%a" (l'équivalent de ton "+%v").
Les extensions de syntaxes ppx dérivent un pretty printer (
pp
) à utiliser comme celui fournit par défaut pour lesint
. Ce qui revient tout à fait au même que votre printf en Go, mais avec un système de types un peu plus sérieux.Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 4. Dernière modification le 19 novembre 2020 à 17:27.
Parce c'est plus simple pour le flot de contrôle et se gère plus naturellement et légèrement avec les structures de contrôle impératives classiques déjà présentes. Go n'est pas un langage où les gens veulent une étude continue de nouvelles fonctionnalités syntaxiques.
La notion de système de types sérieux ou non n'est pas constructive : perso, je comprends que c'est une façon de transmettre ton ressenti et, connaissant bien OCaml, je peux prendre ça avec recul. Mais si je ne connaissais pas OCaml, je pourrais naïvement croire que le système de types de Go est clairement mauvais et croire aux allégations mal informées d'ignorance académique de ses créateurs ou autre : oui, ils ne sont pas des chercheurs en systèmes de types avancés, mais un langage de programmation ne se limite pas à ça.
Le but d'un langage de programmation, ce n'est pas son système de typage, c'est d'écrire des programmes qui répondent à des besoins. Et concernant le typage, tout n'est pas question de puissance, mais aussi d'accessibilité en pratique : c'est pas pour rien que les modules en OCaml sont sous-utilisés et considérés un concept pour non-débutants par rapport aux interfaces Go, accessibles aux débutants, par exemple. Le but des types somme pour les errerus, c'est de bien gérer ces erreurs : d'autres approches comme celle de Go permettent statistiquement de bien gérer les erreurs aussi (voire mieux que les exceptions OCaml), sont-elles moins sérieuses ? La réflection permet grâce au marshalling de sauver facilement un état (par exemple sauvegarde pour un jeu) sans avoir à écrire de code, c'est une application pratique, peu importe le sérieux de l'approche par rapport à une autre approche qui ne propose pas encore d'équivalent simple.
[^] # Re: Raisons d'essayer Rust
Posté par kantien . Évalué à 2.
Je n'ai pas dit que leur système de types est mauvais (ce que tu développes et défend, je l'avais fait à l'époque du journal de gasche que j'ai cité plus haut) mais qu'il n'était pas assez sérieux pour ce que j'aime faire. Tu ne peux pas dire objectivement que les deux systèmes de types de OCaml et de Go sont du même niveau. J'exprime donc une opinion personnelle relative à mes besoins.
Quand tu répètes en boucle que tu apprécies la réflexion pour ses capacités de marshalling, je ne nie pas la chose, ni interdit à toi ou d'autres développeurs d'avoir ce besoin. En revanche, je me permets de répondre que le fait que ce soit intégré de base dans le langage ne m'intéresse pas. J'ai pas le droit d'avoir des goûts distincts des tiens ?
Par contre lorsque tu affirmes que vous avez des types somme, je me permet de le nier objectivement. Que tu veuilles entendre ou non raison m'indiffère, mais la chose n'en reste pas moins vraie. Tu peux tout à fait reconnaître que tu n'en vois pas l'intérêt, et que cela ne te manque pas plus que cela, mais je n'appellerais jamais type somme ce dont vous disposez, tout comme je n'appellerai pas types dépendants ce que l'on fait en OCaml avec des types fantômes.
Pour revenir sur les goûts personnels, je reconnais volontiers qu'un langage ne se limite pas à un système de types, mais je ne suis pas programmeur, et la seule chose qui m'intéresse dans un langage c'est de jouer avec ses types. Avec Go je m'ennuierai vite, avec OCaml je m'amuse : c'est tout ce que je voulais dire par système de types plus sérieux. Tout comme j'adore son système de modules et me moque totalement qu'il soit ou non facilement accessible : je suis mathématicien et logicien de formation et le discours mathématiques est structuré selon le système de modules OCaml depuis Euclide jusqu'à nos jours, je navigue là dedans comme un poisson dans l'eau. Par exemples les concepts de bases de l'algèbre linéaire sont des types de modules :
La seule chose que je regrette étant que le système ne soit pas assez intégré dans le cœur du langage (c'est un langage à part, OCaml c'est deux langages en un), de telle sorte que l'on ne peut pas manipuler vraiment les modules comme des objets de première classe, mais cela évolue dans le bon sens. Avec le systèmes des interfaces, je resentirai un manque dans ma capacité d'expression. D'ailleurs le système est plus puissant que le système des types classes de Haskell, et lorsque Simon Peyton Jones (principal contributeur au compilateur GHC de Haskell) a soutenu le contraire, je me suis permis de le corriger. Ce n'est donc pas ton insistance à affirmer que Go a des types somme qui m'arrêtera.
Enfin concernant l'ignorance académique sur les systèmes de types, j'aimerai me tromper mais c'est vraiment ce que j'ai ressenti à la lecture en diagonale de la PR sur les types somme dont tu as donné le lien. Tu pensais, je te cite, que « mon impression, c'est que tu ne sembles pas saisir les subtilités des interfaces Go » alors qu'il m'a fallu moins de dix minutes de réflexion pour en comprendre la formalisation à partir de ta description. Ce fût plus long pour te convaincre que tel était le cas : relis bien tous mes commentaires.
Pour conclure sur la notion d'abstraction :
Votre type
interface {}
, c'est cela, le concept le plus abstrait, celui de quelque chose : il n'y a plus rien à abstraire, l'ensemble des méthodes étant vide. Raison pour laquelle tu as dis que si tu l'avais choisi au lieu desint
tu aurais eu des listes hétérogènes de choses à la python. Comme cela, une liste de choses :Ce qui montre que le type
top
pourrait s'appeleranything
(enfin ce n'est pas tout à fait celui-ci le type anything en OCaml maistype any = Any : 'a -> any
). Et les concepts c'est la base de la pensée : plus je peux en définir, plus je peux exprimer convenablement ma pensée. Mais un type, en informatique, n'étant rien d'autre qu'un concept… Ou l'on voit d'ailleurs que, déjà en français, la notion de listes s'exprime sous la forme d'un type paramétrique (généricité quand tu nous tiens ;-) : le complément du nom dans les expressions liste d'entiers, liste de course, liste de noms ou liste de choses est lui même un concept, c'est-à-dire un type. ;-)Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 2.
Pour te rassurer, c'est comme cela que je l'ai pris, mais ce n'est pas comme cela que tu l'as écrit, il y avait un point après « sérieux » : facile à interpréter plus génériquement :-)
Oui, mais l'histoire de la réflexion est sortie suite à une question initiale sur les applications intéressantes (au sens général a priori) de celles-ci : à aucun moment je n'ai essayé de te convaincre que ça serait intéressant pour toi en particulier, mais de t'informer à ta demande pourquoi ça l'était pour d'autres. C'est pour ça qu'on se répète, parce que j'ai répondu à cela et tu n'as, par la suite, qu'uniquement insisté sur le fait que tu n'en avais rien à faire et que c'était question de goût, ce qui était HS et donne l'impression que tu te fiches de l'intérêt de la chose en général, même si ce n'est pas ton intention.
Encore une fois, c'est effectivement ce que j'ai imaginé de ta part. Mais ce n'est pas évident dans tes messages. Lorsque tu expliques que pour toi le système de types de Go est un « jouet playskool que l'on donne aux enfants », tu ne dis pas que c'est en comparaison du super jouet bien plus fun qu'est le système de types OCaml. Du coup, quelqu'un qui n'a pas une bonne connaissance de l'historique de tes messages va prendre cela dans le sens que le système de types de Go est un jouet à côté de celui de OCaml : c'est l'interprétation la plus naturelle pour un programmeur, c'est-à-dire les premiers utilisateurs de langages de programmation qui n'imaginent pas forcément que pour d'autres, un langage de programmation, c'est un terrain d'expérimentation pour jouer avec les types. Pour le coup, ils risquent de ne pas trouver ça sérieux, tu es en train de jouer après tout, même si c'est avec un système de types sérieux ;-)
Si tu relis mes messages, tu verras que depuis le début je n'ai pas vraiment affirmé cela (le débat de théorie des typages n'est pas inintéressant pour moi, mais secondaire). Plutôt, j'ai affirmé que je pouvais traiter (ou encoder) avec des types Go les cas d'utilisation (pratique de programmation) des types sommes. Je n'affirme même pas que mon énoncé a un sens propre en théorie des types. Et j'ai fait l'effort de donner des exemples à l'appui pour chaque chose que tu as demandé (en commençant par les listes chaînées), avec l'idée que tu t'intéressais au langage et pas uniquement à faire rentrer son système de types dans ton jeu sur les systèmes de types. Quand j'ai dit utilisation ou pratique de programmation, c'est dans un sens pratique, pas au sens d'un énoncé de typage précis : les cas d'utilisation que j'ai pu rencontrer personnellement, que ce soit dans CompCert en Coq ou dans OCaml (ce que j'ai précisé ensuite). J'ai bien reconnu d'emblée que ce soit plus verbeux, ou l'absence de gestion de la distinction ouverte ou fermée : distinction peut-être capitale pour qui utilise le langage comme plateforme de jeu sur les types, mais distinction beaucoup plus secondaire autrement.
Pour en revenir sur les goûts : si tu relis mes messages sur ce fil, tu verras que je ne parle pas vraiment de mes goûts (je l'ai déjà fait dans le journal), mais de pourquoi, à mon avis, les choses sont ainsi en Go. Concernant mes goûts, vu le journal, c'est assez clair qu'ils sont variés et, suivant ce que je veux faire (jouer avec les types, les tableaux multi-dimensionnels ou développer un logiciel) j'utilise quelque chose de différent. Le système de types de Go n'est pour moi ni meilleur ni pire dans l'absolu que celui d'OCaml : il répond simplement à des besoins et un public différents. Je n'affirme pas par là que leur champ d'application est sans intersection en pratique (ce n'est pas le cas), mais que, globalement, Go est plus un langage dont le design vise à répondre aux besoins des développeurs, alors qu'OCaml vise avant tout à répondre aux besoins des chercheurs en théorie des types.
[^] # Re: Raisons d'essayer Rust
Posté par kantien . Évalué à 1.
Il y a une chose que je ne suis pas dans ce passage de ton commentaire : l'interprétation qu'une personne sans connaissance de l'historique de mes messages est tout à fait correct. Ce système de types est un jouet pour enfant à côté de celui d'OCaml. Je comprends que cela puisse être désagréable à lire, mais c'est bien ce que je pense. Là, c'est le logicien en moi qui s'exprime.
Là logique est une science dont l'objet d'étude est, comme son nom l'indique, le langage. Mais elle ne l'étudie pas à la manière de la linguistique, c'est-à-dire qu'elle ne s'intéresse pas à telle ou telle langues données pour les analyser comparativement dans leurs structures. Si je peut m'exprimer ainsi, ce qu'elle cherche à travers la diversité des langues c'est les invariants par variations. Elle cherche les lois nécessaires de toute pensée, dont le langage n'est que le moyen d'expression. En conséquence, elle n'a pas une approche descriptive comme la linguistique, mais une approche prescriptive et, comme le disait Kant dans le traité qu'il lui a consacré :
L'aspect prescriptif se trouve à la fin de la définition qu'il donne de cette science : « comment il doit penser ».
Ensuite, ce que la logique a à apporter à la programmation et à ses langages, ce n'est pas ce calcul assez simple sur les booléens, mais la théorie des types. Les notions centrales de la logique sont celles de concepts, jugement et raisonnement. Par miroir, ces notions en informatique sont celle de types, jugements de typage et dérivation de typage.
Résultat, quand je regarde le système de type de Go, j'ai une logique tellement amputée de certains de ses concepts et principes, que l'ensemble m'apparaît réellement comme un jouet : la logique sous-jacente est simpliste en comparaison de ce que contient la logique. Ce qui n'est absolument pas le cas avec le système de types d'OCaml (ou Haskell). Ce qui est amusant, au passage, c'est qu'il y a une implémentation de ce systèmes en Go : le cœur du langage c'est le système F et celui-ci constitue le langage de configuration Dhall.
Par exemple, ce qui me manque, en premier, c'est l'absence de jugement disjonctif : la totalité de ce dont nous débattons depuis le début (et même avant que j'intervienne sur ce fil de discussion). La disjonction n'est pas une opération qui prend deux booléens puis en retourne un troisième, mais une opération qui prend deux jugements puis en produit un troisième. La première opération apparait lorsque l'on interprète ces jugements selon leur valeur de vérité, et cette notion n'est pas primitive mais dérivée.
Les jugements disjonctifs donne naissance aux types somme (A ou B), là où les jugements conjonctifs donnent naissance aux types produit comme les
struct
(A et B). Les premiers sont fait pour être utiliser ainsi :Afin d'avoir ce qu'exige l'usage logique des jugements disjonctifs (« il n'est possible ni qu'il y ait en dehors un autre jugement qui soit vrai, ni qu'il y en ait plus d'un parmi eux »), il est nécessaire que le langage, via son système de types, fournisse de manière primitive les sommes fermées, puis qu'il vérifie l'exhaustivité de leur usage.
Dans le reste, on peut aussi lui reprocher de ne pas pouvoir faire abstraction des jugements, c'est-à-dire pas de variables de types ou généricité. Il n'y a pas de sous-typage, le cœur de la syllogistique aristotélicienne : tous les animaux sont mortels, tous les hommes sont des animaux, donc tous les hommes sont mortels.1 L'usage des raisonnements hypothétique (si A alors B) est bien présent au niveau des booléens (if then else) mais ne semble pas être mis si en avant que cela, et moins évident à utiliser qu'OCaml, au niveau des types (ici c'est le type des fonction, comme
f : int -> float
).Je devrais sans doute pouvoir trouver d'autres choses qui me manquent en creusant un peu le langage, mais cela fait déjà beaucoup trop à mon goût. Autant d'absences qui peuvent difficilement me le faire considérer autrement que comme un jouet, relativement à ce que je chercherais à faire avec, quand bien même cette expression pourrait paraître déplaisante à ces utilisateurs.
c'est la combinaison des type sommes avec sous-typage qui nous permettent d'encoder, ce qui relèvent des types dépendants, les droits de lecture et écriture sur un fichier. ↩
Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
[^] # Re: Raisons d'essayer Rust
Posté par barmic 🦦 . Évalué à 3.
De ce qu'il me semble la logique s'intéresse uniquement aux langues formelles et à l'aspect objectif. Ce n'est qu'une petite partie du langage.
Le fait d'être prescriptif c'est une branche de la logique, mais je pense que ça capture bien ce que je trouve profondément gênant avec tes messages. Ça et l'appel continuel aux philosophes, ça ne donne pas vraiment l'impression d'une discussion, mais un étalage de ta science.
Voila c'était plus pour te donner un ressenti que pour en discuter. Bonne soirée
https://linuxfr.org/users/barmic/journaux/y-en-a-marre-de-ce-gros-troll
[^] # Re: Raisons d'essayer Rust
Posté par kantien . Évalué à 2. Dernière modification le 29 novembre 2020 à 22:24.
La logique ne s'intéresse pas, et à aucun moment, uniquement aux langues formelles. Elle s'intéresse à ce qu'il y a de formel dans toute langue (que celle-ci soit naturelle ou artificielle), ce qui constitue bien un aspect objectif du langage. Que ce ne soit qu'une partie, voire même une toute petite partie, de ce qui constitue un langage, je ne l'ai jamais nié et ne le nierai jamais. Ce n'est pas pour autant que c'est une partie à négliger.
Pour ce qui est de la nature de l'analyse logique et des langages dont elles s'occupent, tu pourras, par exemple, te reporter à mon analyse grammaticale du groupe adverbiale dans la langue française. Cela à commencer dans un journal sur la manière d'automatiser la punition consistant à recopier 100 fois la phrase « je ne dois pas jeter d'avion en papier en classe ». La précision « 100 fois » constituant le groupe adverbial (lui-même constitué d'un noyau et d'un complément), c'est-à-dire une précision, ou une spécification, de ce que le verbe « copier » signifie dans une telle phrase. Le début de l'analyse se trouve ici dans le journal à l'origine de la discussion, puis est développée plus en profondeur dans cette dépêche. Tout ce que j'ai écrit à l'époque relève de l'analyse logique du langage, bien que le support sur lequel elle s'exerce soit du français on ne peut plus usuel.
C'est justement parce que l'analyse logique s'applique à tout langage existant qu'elle se permet de prescrire des règles à ceux qui prétendent en inventer de toutes pièces. Libre à chacun de faire fie de ce qu'une science vielle de plus de 2500 ans affirme, mais il faut, dans ce cas, s'attendre à des retours de bâtons ;-)
Le fait d'être prescriptif n'est nullement une branche mais l'essence même de la logique, je ne vois pas à quoi elle pourrait servir d'autre. J'entends bien que tu trouves cela gênant dans mes messages, mais je te rétorque la question : pourquoi ? Dans une autre discussion, tu en es venu à parler d'Einstein et de sa théorie de la gravitation, en expliquant, à bon droit, que ce n'est pas parce qu'une personne avait observé toute sa vie des objets tombés qu'elles comprenait la théorie de la relativité générale. Ceci étant, considérerait-on comme acceptable qu'une personne voulant construire un système de GPS se permette d'ignorer cette théorie et donc l'influence du champ de gravitation sur la marche des horloges (comment synchroniser l'horloge du satellite et celle du récepteur resté sur terre ?) ?
À titre personnel, ce que je trouve gênant est qu'il existe une science vielle de plus de 2500 ans dont certains programmeurs (en particulier certains concepteurs de langages) semblent se moquer. J'entends par « se moquer » non se rire d'elle, mais être indifférent à ce qu'elle prescrit. Et j'ai beau retourner la question dans tous les sens dans ma tête, je n'en comprends pas la raison. Mon appel aux philosophes (je ne vois pas en quoi il a été continuel) n'étant là que pour rappeler cet état de fait : les questions ne datent pas d'aujourd'hui mais ont des siècles de réflexions humaines derrière elles.
À la base tout est partie d'une question, on ne peut plus naturelle, à savoir : comme, de deux chose l'une, un appel de fonction peut réussir ou échouer, pourquoi ne pas répondre par une alternative comme le fait Rust ? Sur cela, comme il s'agit de faire usage d'un type somme1, j'ai généralisé la question : pourquoi Go n'a pas de type somme ? Sur ces entrefaits les réponses qui m'ont été apporté ne m'ont pas convaincues, si ce n'est que les utilisateurs ou responsables du langages (cf la PR mise en lien par anaseto) ne maîtrisaient pas les notions dont il était question.
Je n'ai jamais eu, et n'aurais jamais, la volonté d'étaler ma science en place publique. C'est là une attitude que je trouve soit indécente, soit puérile. En revanche, quand je demande à ce que l'on me montre un chat, puis que l'on me montre un animal qui certes, est un quadrupède, à une queue, des poils… mais qui, quand que je joue avec, se met à aboyer, je réponds que j'ai affaire à un chien et non à un chat.
la disjonction qui se trouve dans l'expression « soit cela réussie, soit cela échoue » est appelée somme en raison du comportement identique de la disjonction et de la conjonction par rapport à l'addition et la multiplication. Lorsque l'on commande un menu au restaurant, l'alternative «(plat et entrée) ou (plat et dessert) » est équivalente à celle-ci « plat et (entrée ou dessert) ». ↩
Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
[^] # Re: Raisons d'essayer Rust
Posté par barmic 🦦 . Évalué à 2.
Alors essayer d'en déduire les formalisme tout en étant préscriptiviste. C'est vouloir en faire des langues formelles.
La première chose à faire, si on cherche à comprendre c'est de se débarrasser de ses apriori1, accepter que ce que l'on prend pour acquis peut être remis en cause. Si ta question c'est "Pourquoi est-ce qu'ils se trompent ?", tu ne trouvera pas grand monde pour t'aider à trouver une réponse. De temps en temps des gens viendront essayer de dialoguer, mais ça va vite tourner en rond.
Il est systématique dans chacun de tous tes commentaires. Quand tu ne cite pas nommément quelqu'un c'est 2500 ans d'histoires qui sont là pour appuyer ce que tu dis.
c'est très facile à dire et très compliqué à faire, on est d'accord ↩
https://linuxfr.org/users/barmic/journaux/y-en-a-marre-de-ce-gros-troll
[^] # Re: Raisons d'essayer Rust
Posté par kantien . Évalué à 2. Dernière modification le 30 novembre 2020 à 01:28.
Mais ce n'est pas du tout ce que je prône, ni ce qu'à jamais prôné la logique. Je ne vois pas où tu veux en venir, ni ce qui pu laisser entendre cela dans mes commentaires. Quoi qu'il y a bien, dans le passé (voire le présent), des logiciens avec une telle ambition mais ils étaient anti-kantien affichés. Donc, je ne vois pas comment je peux être associer à de telles personnes.
Ma question, sur le cas présent, n'était pas spécialement « pourquoi ils se trompent ? », mais pourquoi alors que Colin Pitrat se pose une question que tout homme peut se poser, on lui répond que sa question a une réponse qui n'en est pas une. Et le fait que la réponse n'en est pas une, il l'explicite on ne peut plus clairement dans son commentaire. La seule chose que que j'ai fait, c'est creuser un peu plus la question.
Enfin, je suis loin d'être le dernier à accepter que ce que je prends pour acquis puisse être remis en cause : c'est bien la base de la science après tout. Mais, enfin, quand on se place sur ce terrain là, il vaut mieux avoir du répondant, sinon on se retrouve sur facebook, tweeter ou youtube à avoir des gens qui t'expliquent que le coronavirus est un complot et que le masque est inutile. Et là, effectivement, toute discussion ou dispute (lorsqu'il y a débat) est vouée à l'échec. Mais j'ai bien trop de respect tant pour anaseto que pour toi, depuis le temps que je fréquente ces lieux, pour vous ranger dans ces cases là.
Après tout, il se peut que je me sois emporté parce que c'est un sujet (sur le plan scientifique1, et donc de la rigueur intellectuelle) qui me tient particulièrement à cœur, mais je ne vois pas où j'ai dérapé. Si tu pouvais me l'indiquer (toi ou anaseto), je vous en serais reconnaissant.
Mais parce que la science ne s'est pas faite en un jour. On ne peut pas aborder la savoir en partant du principe que rien ne s'est fait avant nous. Rien que ce qui a donné, par attaque et défense successive, l'informatique prend une partie de ses racines dans la philosophie kantienne et son désaccord avec Leibnitz sur certains points. Voir par exemple cet article de 1905 d'Henri Poicaré, là où il doute de l'espoir de Hilbert qui sera, justement, réduit à néant par Turing 30 ans plus tard. Comment veux-tu que je fasse comme si tout ceci n'avait pas exister ? Dois-je considérer que l'ordinateur est tombé du ciel du jour au lendemain ?
chose assez étrange pour moi, parce que je ne suis ni un scientifique, ni un chercheur, mais il y a certains principes qui me semblent couler comme de l'eau de source (bien plus que certains principes fondamentaux de la physique). ↩
Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 3. Dernière modification le 30 novembre 2020 à 10:30.
J'ai répondu un peu plus bas à des choses proches, mais vraiment, la source de notre différence de perspective est que tu ne considères que l'aspect théorie logique/théorie des types dans tes réponses, alors que nous autres nous intéressons plutôt aux interactions de l'humain avec le système de types et le langage en général.
La question de savoir si l'utilisation des interfaces à la place d'un type somme est équivalente d'un point de vue logique, ou la question d'utiliser un produit pour la gestion d'erreurs plutôt qu'un type somme qui semblerait plus naturel à un théoricien du typage, sont des questions dont les réponses ne fournissent pas d'impact pratique clair. Un choix optimal d'un point de vue langage n'a a priori aucune raison de devoir être compatible avec un raisonnement de logique, puisqu'il s'agit d'une science avant tout humaine : un langage de programmation est une interface entre l'humain et la machine.
Chercher à appliquer des idées de théorie des types est intéressant, mais sans statistiques comparative ni même une intuition des conséquences sur le nombre de bugs ou la productivité dans des contextes réels d'une idée ou l'autre, ce n'est vraiment pas quelque chose qu'on peut espérer pouvoir faire sans faire de concessions aux considérations humaines.
Je t'ai bien donné des réponses diverses à la question d'origine (accessibilité, simplicité du flot de contrôle et annotation facile des erreurs sans introduire de nouvelles syntaxes, analyses statiques qui évitent les soucis en pratique, etc.) pour ces choix et tu résumes le tout à « une réponse qui n'en est pas une » juste parce qu'il s'agit de réponses qui n'ont rien à voir avec la science de la logique.
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 2.
Je crois que ce que tu ne vois pas depuis le début, c'est qu'un langage de programmation est normalement utilisé par des humains pour développer des logiciels. Sa création doit donc être basée non sur une science prescriptive comme la logique, mais sur une science sociale et expérimentale et encore plus vieille, basée sur l'observation des besoins des gens et, en particulier ici, des développeurs. Un système de types puissant n'est pas forcément un système de types qui conduit en pratique à une meilleure productivité ni à moins de bugs. Enfiler une armure de plates avant d'aller couper des oignons pour le repas est contre-productif et n'apporte aucune sécurité supplémentaire à moins de décider d'utiliser une épée plutôt qu'un simple couteau bon marché.
De ce point de vue là, je trouve personnellement que le système de types de Go a fait un meilleur travail que celui d'OCaml. Si j'étais rapide dans mes conclusions comme toi, je pourrais donc dire que les responsables OCaml ne maîtrisaient pas les notions de cette science sociale et expérimentale. Étant plus prudent, je pense plutôt qu'ils avaient des objectifs primaires différents avec ce langage (jouer avec les types et se faire plaisir) et que les besoins des développeurs étaient, à l'époque, beaucoup moins bien connus qu'aujourd'hui.
[^] # Re: Raisons d'essayer Rust
Posté par kantien . Évalué à 1. Dernière modification le 18 novembre 2020 à 00:30.
Je viens de faire un test avec votre version de
Printf
. Cela doit être une question de point de vue, mais pour moi elle est moisie.Le deuxième exemple ne devrait pas compiler! Si je dois abandonner la sécurité du typage statique parce qu'il y a des programmeurs pas capable de définir leur formateur pour les types qu'ils définissent, je préfère rester avec ce que j'ai. ;-)
Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 3.
Tu compares à la version d'OCaml qui n'est pas comparable, car utilise un type format dédié et pas une chaîne de caractères (le fait que l'on écrive ça sous forme de chaîne est du sucre syntaxique). Il n'est pas possible de passer une chaîne de caractères non connue à la compilation en tant que format, par exemple. Ensuite, OCaml utilise des concepts de typage autrement plus avancés que les types sommes (les GADTs) pour réussir à faire une analyse statique de l'input de type format.
Ce n'est pas possible de faire cela en Go de façon générale, puisque Go accepte des chaînes non connues à la compilation en tant que format : il existe des analyses statiques pour chercher des erreurs dans les chaînes de format lorsque ce sont des littéraux.
Par contre, en Go, on a les verbes
"%+v"
et"%v"
qui permettent d'afficher un type quelconque sans avoir à s'inquiéter de leur type, alors qu'en OCaml on n'a pas ça. C'est une question de compromis, difficile de tout avoir.[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 2.
Je n'avais pas réagit sur ça, mais ici il n'est pas question de sécurité du typage statique, mais de sémantique et d'expressivité du typage : en Go Printf est type safe, c'est sa sémantique qui est différente (affichage spécial en cas de verbe de formatage incorrect). Le cas du printf OCaml est, d'ailleurs, assez unique.
On met toujours quelque part la limite pour l'expressivité du typage : c'est un effet Pareto (20% de complexité pour 80% d'avantages), sauf qu'on ne place pas tous cette limite au même endroit (Go, OCaml ou Coq ?). La vérification absolue du format du printf, c'est sympa, mais c'est de la complexité (GADTs), pour quelque chose qui évite des erreurs pas plus fréquentes (et moins graves) qu'une erreur de signe, un accès tableau mal indexé, et bien d'autres erreurs logiques qui ne sont pas traitées en OCaml.
D'autant plus, qu'en l'occurrence c'est de la complexité pour quelque chose où une analyse statique traite la plupart des cas courants : lance
go vet
sur ton exemple et tu auras un warning. C'est une commande de base lancée par défaut normalement à chaque fois qu'on exécute les tests avecgo test
et qui lance un certain nombre d'analyses statiques.[^] # Re: Raisons d'essayer Rust
Posté par Nicolas Boulay (site web personnel) . Évalué à 4.
C'est quand même génial d'avoir une fonctionnalité qui te donne précisément tous les endroits du code à modifier. Si tu utilises des pseudo AST, c'est super utile.
"La première sécurité est la liberté"
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 3. Dernière modification le 17 novembre 2020 à 10:24.
C'est très sympa, mais je pense personnellement que ce serait mieux sous la forme d'un warning ou d'une analyse statique : ça permet de trouver tous les endroits à modifier tout en permettant les modifications graduelles. Ça donnerait les avantages sans les inconvénients.
[^] # Re: Raisons d'essayer Rust
Posté par Nicolas Boulay (site web personnel) . Évalué à 3.
Le problème pour ton changement graduel, c'est que même si le code compile, il est faux.
"La première sécurité est la liberté"
[^] # Re: Raisons d'essayer Rust
Posté par anaseto . Évalué à 3.
Pas forcément, lorsque tu ajoutes un nouvel habitant au type somme, cet habitant n'est encore jamais produit par le programme. Tu fais un commit. Tu continues petit à petit à ajouter les cas traitant ce nouvel habitant avec des commits régulièrement. Quand tous les cas ont été gérés (plus de warnings), on peut enfin ajouter du code qui produit effectivement cet habitant.
[^] # Re: Raisons d'essayer Rust
Posté par octachron . Évalué à 2.
Dans le détail, les
let
(etand
s) monadiques d'OCaml sont un peu plus que du sucre syntaxique: ils sont encore explicitement présent dans l'AST après le typage, afin d'avoir de meilleur messages d'erreurs. Typiquement, ils sont élaborés en une forme plus primitive dans la même passe qui transforme le filtrage de motif en une imbrication de tests et sauts.# La pizza métal
Posté par chimrod (site web personnel) . Évalué à 9.
Ce journal est une invitation à venir critiquer en disant : "mais non t'as rien compris, ce langage est beaucoup plus riche que ce que tu as pu tester, la preuve …" mais comme certains le feront mieux que moi, je m'en vais relire la petite BD de Boulet pendant ce temps.
Sinon qu'est-ce qui t'attire dans le fait de tester différents langages comme ça ? Je suppose qu'en prenant le temps de te familiariser avec l'environnement, installer une chaîne de compilation, découvrir les librairies,, voir comment tout ça s'articule ça doit te demander pas mal de temps ?
Ton journal m'a donné envie de découvrir J, je sais pas j'ai comme une sorte de fascination pour APL, il faudra un jour que je m'y mette.
Et sinon, pour troller un peu, de mon côté j'aime beaucoup OCaml. Le langage me permet de mettre tellement de contraintes dans mon code, qu'au moment où il compile enfin j'ai l'impression d'avoir traversé l'Amazonie avec mon briquet et mon couteau.
[^] # Re: La pizza métal
Posté par gUI (Mastodon) . Évalué à 4. Dernière modification le 14 novembre 2020 à 08:39.
ah putain qu'est-ce que j'ai ri :)
sinon pour revenir aux coming out des langages, je me mets au Python : bin j'aime vraiment bcp en fait. je suis en train d'arriver dans la phase où je trouve le langage de plus en plus simple parce que je comprends comment ça marche derrière ("bin évidemment qu'on peut pas indexer des listes par des objets mutables, vu qu'il y accède par des hash").
En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.
[^] # Re: La pizza métal
Posté par anaseto . Évalué à 6.
Héhé, peut-être bien :-) Le côté que j'aime bien, c'est qu'on découvre que certaines features sont super importantes pour certains, secondaires pour d'autres, voire pas rentables. Parfois, ça donne des pistes sur le type d'utilisation qui est donnée au langage, ou le background du programmeur. D'autres fois, ça nous montre juste à quel point le ressenti est individuel et l'importance des goûts et sentiments en programmation : se sentir à l'aise et épris d'affection avec un langage, indépendamment de l'objectivité statistique du sentiment, c'est important si on va passer beaucoup d'heures avec.
Les langages de programmation, c'était un de mes passe-temps pendant quelques années. Tout comme toi avec APL, j'avais une sorte de fascination sur les différentes idées qui pouvaient exister pour représenter un programme. Et puis j'aimais tester suffisamment pour ressentir personnellement le truc, découvrir l'effort cognitif que le langage me demande, l'impact des différentes idées sur ma façon de programmer, découvrir la communauté, les outils, tout en jouant le jeu : essayer d'écrire du code idiomatique, ne pas fuir les exceptions ou les modules/foncteurs en OCaml, ni les monades/type class/foncteurs en Haskell, profiter des effets de bord et de la syntaxe flexible en Perl, programmer de façon fonctionnelle et tacite en J, ne pas fuir les macros en Tcl ou Lisp, ne pas essayer d'implémenter les monades en Go, ce genre de choses.
Si tu aimes APL pour ses primitives (et que tu n'étais pas attaché à l'utilisation de symboles Unicode), tu devrais trouver effectivement ça intéressant : beaucoup de primitives sont des généralisations de celles d'APL, et le langage est, en général, plus fonctionnel (de quoi plaire à un OCamliste !), avec pas mal de fonctions d'ordre supérieur (qu'ils appellent adverbes et conjonctions) et la possibilité de définir les siennes facilement.
C'est un bon exemple de ce que je dis plus haut : bien qu'on n'évalue pas précisément le temps que nous sauve la richesse extra des types en OCaml par rapport, par exemple, à Go, en fonction de comment on ressent le fait de devoir débugger un nil raté de temps en temps ou un switch non exhaustif, on va soit trouver ça génial (j'étais comme toi ici à une époque), soit être assez indifférent (je suis proche d'ici maintenant), voire trouver ça pas rentable (par exemple quelqu'un pour qui réussir à compiler du OCaml est pénible, à cause des messages d'erreur un peu difficiles).
D'ailleurs, je sais pas trop pourquoi mon ressenti sur nil ou le check d'exhaustivité des filtrages par motif a évolué. Peut-être que je fais moins d'erreurs maintenant ou que je programme des trucs différents qu'avant ?
# Zig
Posté par rewind (Mastodon) . Évalué à 7.
Je jette un œil sur Zig aussi de temps en temps. La documentation de la bibliothèque standard n'est pas très facile à lire, et cette même bibliothèque standard est un peu un gros foutoir. Mais en dehors de ça, je trouve que ce langage a plein de trucs très intelligents qui manquent cruellement au C. Je trouve aussi que la compatibilité avec le C est super bien foutue : pouvoir importer un header C et l'utiliser directement en Zig, chapeau. Ça donne envie d'essayer des choses.
# termes de programmation
Posté par Matthieu Duchemin (site web personnel) . Évalué à 7.
Ce journal fait référence à de nombreux termes avec lesquels je ne suis pas toujours à l'aise (voir que je ne connais pas du tout). Pour exemple: Typage expressif, traits, fonctions non récursives terminales, langages fonctionnels …
Je sais pondre du code, mais j'aimerais améliorer mes connaissances en programmation, et j'ai la sensation que mieux maîtriser ses différents termes, et donc les concepts qui vont avec, m'aiderai à y arriver.
Est ce que vous connaîtriez des ressources sur le web ou des livres qui abordent ces aspects et surtout qui seraient assez exhaustif ?
[^] # Re: termes de programmation
Posté par anaseto . Évalué à 3.
C'est une bonne question. Je dois dire que je ne pense pas avoir appris la plupart de ces termes dans un livre ou ressource unique. La plupart du temps, c'est en lisant des articles de blog de la communauté d'un langage spécifique qu'on découvre les termes (en sachant que, parfois, d'un langage à un autre, les termes peuvent avoir des sens un peu différents, comme pour les traits ou interfaces). Souvent l'article n'explique pas le terme, donc on cherche sur wikipédia, ou on tombe sur stackoverflow ou ailleurs.
Le wikipédia anglais est vraiment pas mal pour ce genre de choses, par exemple, pour le typage on va facilement trouver des liens vers tous les termes typiques (typage dépendant, graduel, dynamique ou statique, fort ou faible, inféré etc.). Par exemple, un système de typage est dit expressif s'il permet de décrire des pratiques, contraintes et structures complexes ; c'est un terme un peu vague. En particulier, un typage expressif permet d'écrire plus de programmes de façon type safe, ce qui veut dire en pratique en détectant plus d'erreurs à la compilation.
[^] # Re: termes de programmation
Posté par chimrod (site web personnel) . Évalué à 3.
De mon côté, venant du monde Java et de la programmation objet j'ai commencé en m'intéressant aux design patterns. Je voulais savoir ce qui faisait qu'une manière de coder était reconnue comme un patron de conception, ou savoir si les designs pattern étaient uniquement disponibles dans la POO ou est-ce que d'autres langages proposent des choses radicalement différentes (ça ressemble à quoi un design pattern fonctionnel, et en programmation logique ?)
Je suis tombé sur le typeclassopedia d'Haskell, que j'ai lu et qui m'a donné un mal de tête comme j'en avait jamais connu jusqu'alors. Et en même temps, j'avais l'impression de découvrir quelque chose de complètement différent et que j'avais la une clef pour mettre en relation plein de concepts différents.
C'était aussi l'époque où Scala venait prenait son envol, et il y avait plein d'articles de blog qui présentaient des concepts relativement communs pour qqn faisant de la programmation fonctionnelle, mais accessible pour qqn venant de java. (un article que j'ai retrouvé de mémoire et qui m'avait aussi marqué à l'époque : The Essence of the Iterator Pattern ) Je pense que maintenant ça doit continuer sur d'autres supports d'autres sources, à chercher…
Bref, un peu de curiosité, suivre les tendances du moments en fonction des langages qui sortent et faut essayer de choper le train en marche, de toute façon tout se recycle en continue : les concepts ont été posés il y a maintenant plus de 40 ans, ils ont juste muris entre temps !
[^] # Re: termes de programmation
Posté par _kaos_ . Évalué à 5.
Salut,
Moi, ce qui m'énerve le plus, c'est les mots où on peut mettre tout et n'importe quoi, comme framework.
J'ai toujours une hésitation quand on me demande si j'ai utilisé un "framework" : on parle technique (librairie ?), organisationnel (méthodologie ?), ou est-ce une question pour placer un mot qui n'a pas de sens mais qui fait cool ?
;)
Matricule 23415
# Common Lisp: corrections
Posté par dzecniv . Évalué à 4.
Salut,
Common Lisp est un langage multi-paradigme, pas purement fonctionnel donc, compilé et fortement typé, qui permet du typage graduel, tout en utilisant son excellent REPL (devrait-on dire, image-based development). Mais il ne fait pas autant d'inférences de typage que les langages modernes (Haskell et cie). Pour cela des librairies émergent… (https://github.com/stylewarning/coalton/)
À noter que comme on code avec le REPL à côté, on compile notre code fonction par fonction avec un raccourci clavier… c'est terriblement efficace.
Il existe aussi typed-racket.
Carrément. Les articles de blog qui montrent que Common Lisp peut être autant ou plus efficace que du C affluent (oui oui, on croule dessous :p ). Car Common Lisp permet de déclarer ses types un peu partout, quand on veut. On peut vraiment partir à la chasse à l'optimisation.
Je ne suis pas dans ces débats, donc perso je m'en fiche. Pour se protéger, on utilise le système des
gensym
pour déclarer une nouvelle variable dans une macro, qui aura donc un nom unique, et voilà.Je suppose que tu voulais dire "un peu plus impératif" ! Exemples de loop, qu'il faut apprendre par l'exemple: https://lispcookbook.github.io/cl-cookbook/iteration.html
Oui, Quicklisp, comme d'autres librairies, est marqué "beta software" mais il est pleinement fonctionnel. Il n'est marqué beta que parce la communauté Common Lisp joue le jeu de la stabilité à fond. Un programme stable va durer des décennies. Il n'est pas rare qu'un programme écrit dans les année 90 (soit juste après la standardisation ANSI du language) tourne toujours sans modification. Personnellement j'ai vu des warnings de dépréciation rester pendant 16 ans ! Compare cela aux langages d'aujourd'hui, comme Python…
Par ailleurs, Quicklisp est un peu différent des autres gestionnaires de librairies. Il fonctionne en "releases" mensuelles, un peu comme apt. Il garantit que les librairies d'une même release peuvent s'installer ensemble.
Notez que des alternatives avec un autre modèle émergent: Ultralisp, CLPM…
[^] # Re: Common Lisp: corrections
Posté par anaseto . Évalué à 3.
Oui, ils ne sont pas purement fonctionnels (OCaml non plus, ni même vraiment Haskell). Par contre même si le typage est fort, ils sont, de base, typés très dynamiquement (il est possible d'écrire des expressions, autres que des casts, qui vont produire une erreur de typage à l'exécution, ou changer impérativement le type d'une variable, par exemple). La notion de typage fort n'est d'ailleurs pas bien définie, j'imagine qu'ici ce que tu veux dire c'est l'absence de conversions implicites et autres caractéristiques de typage laxistes (qu'on peut retrouver dans C qui lui est statiquement typé, mais faiblement), ou peut-être la possibilité d'écrire certaines déclarations optionnelles de types (mais qui, en général, ne sont pas toujours validées statiquement).
C'est pour cela que j'avais précisé « par défaut », car, effectivement, à l'aide des macros on peut construire, a posteriori, du typage statique (comme pour typed-racket). Mais je suis content que tu le mentionnes, car construire un système de typage avec des macros, c'est quand même une chose impressionnante et qui mérite d'être connue !
Oui, sauf que pour le coup, même si SBCL fait un peu d'inférence, elle n'est pas complète ni garantie, ce qui veut dire qu'il faut choisir un degré de safety pour les déclarations (safety 0) si on veut optimiser agressivement : on risque alors de ne pas être type safe. À utiliser avec modération :-)
Oups, oui, bien sûr !
Concernant Quicklisp et les bibliothèques, je suis allé un peu vite et mon impression est peut-être faussée, ça fait longtemps que j'ai pas plongé dedans.
# Null safety
Posté par ff9097 . Évalué à 4.
Une des choses que j'ai découvert assez récemment et qui est un gros progrès c'est le principe de null safety. C'est a dire la différenciation entre un type null et non-null. Et l'obligation de gérer la valeur null quand elle est possible. Les erreurs "null pointer exception" sont parmi les plus fréquentes. Ce qui permet un code bien plus robuste aux erreurs. Un peu comme le typage statique par rapport au dynamique.
J'ai beaucoup aimé remplacer le Java par du Kotlin grâce à ça. Mon code est bien plus robuste depuis
# Suggestion pour tes prochains tests
Posté par devnewton 🍺 (site web personnel) . Évalué à 4.
https://crystal-lang.org/
https://vale.dev/
https://odin-lang.org/
https://www.java.com/fr/
https://castle-engine.io/modern_pascal_introduction.html
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
[^] # Re: Suggestion pour tes prochains tests
Posté par chimrod (site web personnel) . Évalué à 2.
Trop gros, passera pas.
# merci pour ton retour, cela étant dit...
Posté par Selso (site web personnel) . Évalué à 1.
J'ai une petite remarque concernant la formulation "ceci dit" utilisée plusieurs fois à tord dans cet article (un tic ?)
Quelques explications données par le Figaro.
[^] # Re: merci pour ton retour, cela étant dit...
Posté par anaseto . Évalué à 2.
Tiens, je connaissais pas cette histoire (ou j'ai oublié). Ceci dit (haha), le wiktionnaire, assez descriptif plutôt que prescriptif dans son approche, documente l'expression, en mentionnant bien cependant que certains « puristes » y trouvent effectivement quelque chose à redire :-)
Personnellement, d'un point de vue linguistique, j'ai l'impression que « cela » est en voie de disparition de la langue (orale), remplacé par « ça » la plupart du temps, ou « ceci » dans certaines expressions (« ça dit », qui serait la contraction théoriquement « correcte » ne s'utilise pas, il me semble).
[^] # Re: merci pour ton retour, cela étant dit...
Posté par Selso (site web personnel) . Évalué à 1.
Je ne me dirais pas puriste car je fais beaucoup d'erreurs (sic), mais quand tu prends conscience des bonnes formulations, tu t'inquiètes des ravages que peut causer la pratique négligente de notre langue.
On s'entend que l'on est loin du cas de Booba (non pas le petit ourson), mais si on se laisse aller tu conviendras que l'on s'étonnera de moins en moins du manque d'élégance dans notre façon de s'exprimer.
Cela étant dit, merci pour encore pour ton retour d'expérience.
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.