2 points par GN⁺ 2024-05-27 | 1 commentaires | Partager sur WhatsApp
  • Hurl est un langage de programmation expérimental qui construit le flux de contrôle uniquement à partir de la gestion des exceptions, au lieu des branchements ou boucles habituels
  • Le projet est né d’une conversation entre Nicole Tietz-Sokolskaya et des amis du Recurse Center, et le site propose à la fois une documentation d’utilisation, des exemples, un guide de débogage et une FAQ
  • Les citations mises en avant sur la page de présentation, comme “monstrosity is beautiful” ou “Certified unhinged™”, assument pleinement une ambiance volontairement humoristique
  • Le code source de Hurl et du site est public, mais l’envoi de patchs par e-mail exige une cession des droits sur les patchs
  • Le projet est proposé au choix sous AGPL-3.0, GAL-1.0 ou une licence commerciale

Une expérimentation de langage qui ne garde que les exceptions

  • Hurl a été créé avec un seul objectif : explorer s’il est possible de concevoir un langage reposant uniquement sur un flux de contrôle basé sur les exceptions
  • L’idée est née d’une conversation entre Nicole Tietz-Sokolskaya et des amis du Recurse Center, dont l’identité n’est pas révélée « par décence »
  • Le site fournit une documentation sur l’utilisation de Hurl, des exemples, un guide de débogage et une FAQ

Un projet qui ressemble à une blague, mais qui est réellement publié

  • La page de présentation affiche plusieurs citations qui révèlent bien le ton de Hurl
    • “This monstrosity is beautiful, and I must never touch it”
    • “Certified unhinged™!”
    • “is "🤮" an available quote?”
  • Si vous souhaitez ajouter une citation, il faut envoyer un e-mail à Nicole, avec un consentement explicite pour l’inclusion de la citation

Code source et conditions de licence

  • Le code source du langage Hurl et de ce site est publié dans Hurl's repo
  • Si vous trouvez un bug ou une erreur, vous pouvez envoyer un patch par e-mail, mais vous devez céder tous les droits sur ce patch
    • Cette condition vise à préserver la possibilité de relicencier le projet et de proposer une licence commerciale
  • Le projet peut être utilisé sous l’une des trois licences suivantes
    • AGPL-3.0

      • GAL-1.0 : Gay Agenda License
      • licence commerciale
      • Lors de l’examen des licences, des joke licenses et des unfortunate licenses ont aussi été envisagées, mais ce sont finalement ces trois licences qui ont été retenues

1 commentaires

 
GN⁺ 2024-05-27
Avis de Hacker News
  • Si je concevais un langage de programmation, j’imposerais des espaces de noms pour les include/import, et si possible j’empêcherais aussi les effets de bord au niveau supérieur
    Il est beaucoup plus facile de raisonner avec quelque chose comme let foo = include "lib/foo.hurl", puis un appel à foo.init()
    À l’inverse, si include "lib/foo.hurl" // side effects est suivi de baz(buz), il devient difficile de savoir si les fonctions et variables viennent de la bibliothèque standard ou d’un include quelconque

    • En l’absence de liaison explicite des noms, il vaudrait mieux imposer que l’instruction import corresponde à l’espace de noms
      import "foo/bar" devrait permettre d’utiliser foo.* ou bar.*, pas de voir apparaître bazz.*. Go me vient immédiatement à l’esprit
    • Je ne suis pas forcément en désaccord, mais IntelliJ, que j’utilise au travail, montre clairement d’où vient chaque référence importée et permet d’y aller avec un raccourci
      VSCode peut faire quelque chose de similaire avec des plugins et le LSP, mais nettement moins bien. La navigation dans le code est tellement lente que je ne peux pas travailler avec VSCode
      Je me demande si ce genre de proposition n’est utile que lorsqu’on n’a pas ces outils. Au moins dans un environnement pro, il me semble impossible de vivre sans eux
    • Avec ça, on peut passer des paramètres à foo.init(), ce qui est impossible avec un import brut
    • Si le contrôle de flux d’un langage est centré sur les exceptions, le bateau du « facile à raisonner » a probablement déjà pris le large
      Ça ne veut pas dire que ce projet est sans valeur ; au contraire, je le vois plutôt comme une œuvre d’art
    • D’accord à 100 %
      J’ai déjà forké Ruby pour faire en sorte que require n’écrase pas la table des symboles, mais l’écosystème Ruby m’a semblé dépendre beaucoup trop d’un état global mutable partagé, au point que j’ai fini par perdre tout intérêt pour Ruby lui-même
  • Je n’ai jamais aimé les exceptions, parce qu’elles rendent difficile la compréhension du contrat entre l’appelant et l’appelé, et augmentent aussi le couplage du code
    Je préfère l’approche qui passe par les valeurs de retour, comme en Go ou en Rust. En survolant le langage, je ne sais pas trop s’il y a quelque chose qui résout ce problème
    Si l’IDE pouvait déterminer dynamiquement toutes les exceptions non interceptées d’une fonction et permettre de sauter aux endroits où une exception peut être levée, ce modèle pourrait être acceptable. En revanche, je ne sais pas comment gérer le couplage, et le graphe de flot de contrôle risque de devenir extrêmement instable

    • En Java, IntelliJ fait exactement ça. S’il y a une fonction qui lève une exception et qu’elle n’est pas interceptée par un appelant quelque part dans le projet, il le signale comme un problème, et il est facile de naviguer vers l’implémentation ou les sites d’appel
      Cela dit, en Java, sauf si elle hérite de RuntimeException, une exception qu’une fonction peut lever fait partie de sa signature. Dans ce cas, si on lève une exception sans l’ajouter à la signature, ça ne compile pas
      Les conditions de Java rendent beaucoup plus simple pour un IDE de signaler les exceptions non interceptées, mais pour les exceptions qui ne sont pas des exceptions d’exécution, c’est un problème soluble par analyse statique
      À l’inverse, retourner des valeurs enveloppées standardisées Ok/Err paraît plus simple, à la fois pour l’outillage et pour le confort des développeurs
    • Il n’y a littéralement aucune différence entre lever une exception et retourner une exception sous forme de variable
      La seule différence, c’est qu’avec la transmission d’exceptions, le compilateur écrit le code répétitif à votre place, alors que sinon vous devez l’écrire à la main
      Je ne comprends absolument pas pourquoi, en 2024, quelqu’un doté d’un cerveau qui fonctionne normalement voudrait faire ça à la main
    • J’aurais probablement préféré Go s’il n’avalait pas aussi naturellement le contexte des erreurs
      Pendant la période où je l’ai utilisé, trouver la cause racine sans débogueur était bien plus pénible
  • L’exemple de toss est présenté comme « surtout utilisé pour transmettre plusieurs valeurs hors d’une fonction ; pas indispensable mais mignon », alors qu’il n’est pas du tout inutile : il implémente des générateurs résumables
    Bien sûr, si l’on veut leur faire faire autre chose qu’une reprise immédiate, cela peut devenir assez intéressant. Il suffit de structurer toute la base de code autour de la pile interne-externe de toss

    • Ce n’est pas exactement la même chose. Un générateur résumable peut être repris à n’importe quel point ultérieur du programme, alors qu’ici return doit être lexicalement scopé du côté du gestionnaire
      Par exemple, en Python, on peut appeler next() depuis n’importe où
      Cela ressemble davantage au passage d’un callback par un canal latéral. toss appelle ce callback, et return retourne littéralement depuis celui-ci
    • C’est exactement la première chose qui m’est venue à l’esprit en lisant
      On pourrait presque croire à une blague : dans d’autres langages, ce serait une fonctionnalité vraiment utile, et ici c’est traité comme un petit gadget mignon dont on pourrait se passer
    • Ça ressemble davantage à de la propagation d’événements basée sur la pile
    • Comme le yield de C# ?
    • Même première impression. Un petit langage sympa avec des générateurs, pourquoi pas
  • Hurl semble assez proche du système de conditions à la Smalltalk ou Common Lisp
    Dérouler la pile et reprendre ne sont que deux redémarrages possibles parmi d’autres : https://gigamonkeys.com/book/beyond-exception-handling-condi...

  • Indépendamment du projet lui-même, je suis fermement convaincu que le monde irait mieux si davantage de choses utilisaient l’extension .wtf pour leur domaine

  • Ça ressemble à une forme faible d’effets algébriques, mais c’est tout de même chouette de voir ce genre de langage et ce qu’on peut faire avec

    • Je n’ai jamais compris les effets algébriques, mais la documentation de Hurl, elle, je la comprends
      Si les effets algébriques sont essentiellement quelque chose comme le mot-clé toss de Hurl, je me demande en quoi ils sont plus puissants que toss
  • Expérience de pensée intéressante
    Je déteste vraiment les exceptions, et je veux un langage sans exceptions
    Les exceptions sont le goto de notre époque
    Avec Maybe/Option et Effect/Result, il y a très peu de raisons de lever des exceptions et de devoir suivre mentalement où elles seront traitées
    Je m’inquiète un peu que les effets algébriques gagnent en popularité et influencent aussi le JS frontend, déjà bien trop complexe, parce qu’ils encouragent à lancer des « exceptions » pour contrôler le flux
    Si tout ça vise à éviter le problème de couleur asynchrone/synchrone, personnellement je ne trouve pas que ça en vaille du tout la peine

  • Wow, je n’aime pas ça. Et pourtant, bizarrement, il y a quelque chose de presque élégant
    C’est très difficile à modéliser mentalement, mais quand même
    Plus sérieusement, j’aimerais qu’il y ait des syntaxes catch différentes pour les exceptions résumables et non résumables. Cela supprimerait l’ambiguïté syntaxique sur le fait que return renvoie ou non le flux de contrôle vers le lanceur de l’exception immédiate la plus proche
    Et la bibliothèque standard ne devrait pas se réfugier dans des fonctions classiques qui retournent des valeurs. Ce n’est pas parce que goûter sa propre cuisine donne des brûlures d’estomac qu’il faut refuser d’en manger

    • Oui. Cela dit, une autre possibilité serait que la syntaxe fasse automatiquement un catch quand une fonction est appelée à un endroit où une valeur est attendue
  • Est-ce que je comprends bien : ce qui est hurl peut être intercepté, mais ce qui est toss ne peut pas l’être ? Il va me falloir un peu de temps pour m’y habituer
    Je m’inquiète aussi de savoir combien de Hurl il faudra que j’écrive avant que les gens commencent à m’appeler tosser

  • Toss a l’air d’une construction de langage intéressante. Elle remonte la pile à la recherche d’un gestionnaire d’exceptions, puis revient à l’emplacement d’origine et reprend l’exécution comme si de rien n’était
    Cette construction semble permettre d’injecter des comportements supplémentaires à l’exécution
    Habituellement, dans le code orienté objet, on fait de l’injection de dépendances via les constructeurs de services ; toss permettrait-il de faire ça avec des « gestionnaires de toss » ?

    • Il faut regarder Koka. C’est un « vrai » langage avec un système d’effets algébriques
      https://koka-lang.github.io/koka/doc/book.html#why-handlers
    • C’est assez proche du système de conditions de Common Lisp
      Je ne le connais pas très bien, mais je sais qu’il permet d’injecter des comportements à l’exécution de cette manière
    • Ça ressemble au Resume Next de VB