3 points par GN⁺ 25 일 전 | 1 commentaires | Partager sur WhatsApp
  • Petit langage utilisant une syntaxe de style Rust tout en s’exécutant sur le runtime Go, avec l’ambition de combiner les atouts des deux langages
  • Une architecture qui renforce la sûreté et la puissance d’expression grâce aux types de données algébriques, au pattern matching, au système de types Hindley-Milner et à l’immutabilité par défaut
  • L’import direct de packages Go, l’opérateur de pipeline, les blocs try et la concurrence basée sur task assurent l’interopérabilité avec l’écosystème Go
  • La détection d’erreurs à la compilation, des messages de diagnostic explicites et la prise en charge du LSP améliorent à la fois l’expérience développeur et la stabilité du code
  • Point clé : le code Lisette est transformé en code Go clair et lisible, ce qui permet une intégration naturelle dans des projets Go existants

Présentation de Lisette

  • Lisette est un petit langage basé sur une syntaxe Rust et compilé vers le runtime Go
  • Il se caractérise par les types de données algébriques, le pattern matching, l’absence de nil, le système de types Hindley-Milner, l’immutabilité par défaut et l’interopérabilité avec l’écosystème Go
  • Installation possible avec la commande cargo install lisette, et utilisation directe de packages Go comme fmt, io ou os via import

Une syntaxe familière

  • Il adopte une structure syntaxique proche de Rust
    • prise en charge du pattern matching via enum et match
    • définition de méthodes possible avec des blocs struct et impl
  • C’est un langage orienté expressions : if, let et les blocs renvoient tous une valeur
  • Il prend en charge le chaînage et les lambdas, ce qui permet d’exprimer de manière concise le traitement des variables d’environnement ou la manipulation de chaînes
  • Il gère les interfaces et les génériques, avec définition de interface et écriture de fonctions génériques via des contraintes T: Trait
  • Les syntaxes if let et let else permettent de traiter simplement le type Option

Sûreté

  • Détection à la compilation d’erreurs susceptibles de survenir dans le runtime Go

    • une erreur est produite si tous les motifs ne sont pas couverts dans une instruction match
    • l’usage de nil est impossible, les valeurs manquantes étant représentées par Option<T>
    • un avertissement est émis si une valeur de retour Result est ignorée
    • un avertissement est émis si un type privé est exposé dans une API publique
    • une erreur survient si une variable immuable est transmise comme argument mutable
    • l’oubli d’un champ de structure provoque une erreur de compilation
    • les messages de diagnostic fournissent l’emplacement précis dans le code et des suggestions de correction
    • la prise en charge du LSP (Language Server Protocol) permet l’utilisation dans les principaux éditeurs comme VSCode, Neovim ou Zed

Utilisabilité

  • Conçu avant tout pour l’interopérabilité avec Go
  • L’opérateur de pipeline (|>) permet d’exprimer simplement le chaînage de fonctions
  • Les blocs try simplifient la propagation des erreurs
  • La concurrence s’appuie sur task et Channel, dans un modèle proche des goroutines de Go
  • Des attributs de sérialisation permettent de définir les noms de champs JSON, leur omission, leur conversion en chaîne ou encore des tags de validation
  • Un bloc recover est fourni pour la récupération après panic, avec un traitement sûr des erreurs via le type Result
  • La syntaxe defer est prise en charge pour garantir le nettoyage des ressources ou le rollback de transactions

Un résultat de compilation transparent

  • Le code Lisette est converti en code Go clair et facile à lire
    • les types Option et Result sont respectivement transformés en structures lisette.Option et lisette.Result
    • les instructions match sont converties en conditions Go traitant chaque branche
    • l’opérateur ? est remplacé en interne par du code de vérification de Result
  • À titre d’exemple, la fonction classify reçoit un Option<int> puis est convertie en conditions Go explicites, tandis que la fonction combine devient du code Go qui vérifie Result

Informations supplémentaires

  • dépôt officiel : github.com/ivov/lisette
  • publié sous licence MIT, le projet est développé par Iván Ovejero en 2026

1 commentaires

 
GN⁺ 25 일 전
Avis sur Hacker News
  • J’ai discuté avec l’auteur et, même si je n’ai pas testé le langage moi-même, Lisette me semble intéressant et clairement meilleur que Go sur certains points.
    Cela dit, je pense qu’il est difficile de dépasser complètement les limites de Go. Par exemple, le problème du typed nil lié aux types d’interface de Go est traité avec des Option dans Lisette, mais le double déballage (Some(Some(h))) peut devenir maladroit.
    De plus, la manière dont Go gère defer reste peu pratique et ne permet pas une libération automatique des ressources comme avec le RAII.
    Si TypeScript a complété JavaScript, c’est parce qu’il n’existait pas d’alternative exécutable dans le navigateur ; aujourd’hui, avec WASM, la situation est différente.
    Du coup, je me demande : « puisqu’il y a Rust, pourquoi rendre Go plus proche de Rust ? » Cela dit, Lisette semble viser un entre-deux.
    Au final, Lisette paraît adapté à ceux qui veulent améliorer une base de code Go existante ou continuer à utiliser le runtime Go.
    Ce qui m’interpelle, c’est l’absence d’un guide de démarrage rapide répondant à la question : « comment commencer à écrire le fichier suivant en Lisette plutôt qu’en Go ? »
    Billet de blog lié : Go is still not good

    • Go reste unique en son genre parce qu’il fournit un runtime de concurrence basé sur le GC.
      Dans les domaines où l’on manipule des graphes de références complexes, le GC est indispensable, et la structure de pile en mode utilisateur de Go lui donne un modèle mémoire efficace.
    • Avec un langage à GC, on développe bien plus vite. J’ai créé un chatbot en Rust et en Python ; malgré mon expérience en Rust, Python a été nettement plus rapide.
      Go convient aussi très bien pour créer rapidement des outils CLI — par exemple : wordle-tui
    • Go a beaucoup d’aspects bizarres en tant que langage, mais c’est une excellente cible de compilation.
      La syntaxe est simple, le support multiplateforme, le runtime et le GC sont intégrés, la structure « errors as values », les green threads, le compilateur AOT rapide, etc., sont autant d’atouts.
      Le defer de Go est utile, mais la gestion des erreurs et les règles de portée restent maladroites.
    • La formule du billet de blog disant que « Go est un langage qui a recréé NULL par erreur deux fois » m’a marqué.
      TypeScript n’a pas non plus résolu ce problème, et c’est même pire. J’ai donc créé moi-même un package de type Option et je l’ai publié sur NPM → fp-sdk
    • L’async de Rust est moins pratique que celui de Go à cause de l’absence de GC. Rien que pour ça, il y a une raison de choisir le runtime Go.
  • Il existe déjà plusieurs langages qui compilent vers Go — XGo, Borgo, Soppo, etc.

    • Borgo et Lisette remplacent simplement le retour (T, error) par un type Result, mais sémantiquement ce n’est pas tout à fait équivalent.
      Par exemple, dans io.Reader.Read, (n!=0, io.EOF) signifie une fin normale ; si on le traite simplement comme une erreur, on obtient un comportement incorrect.
    • Je me demande comment les erreurs de compilation de la langue cible sont remontées vers le langage source.
  • La qualité des messages d’erreur de Lisette est impressionnante. Les indications « help » semblent réellement utiles.
    En revanche, je crains que le code transformé en Go ne devienne verbeux, et qu’en cas d’erreur à l’exécution il faille déboguer dans le code Go.
    Il semble aussi difficile d’appeler Lisette depuis du code Go existant.
    Je me demande si Lisette est un langage expérimental ou s’il vise réellement la production.

    • Le développeur a répondu directement : avec l’option lis run --debug, des commentaires //line source.lis:21:5 sont insérés dans le code Go, ce qui permet de faire correspondre les stack traces au code Lisette d’origine.
      Le LSP gère les erreurs de compilation à partir des fichiers .lis.
      Pour l’instant, il n’existe pas de fonctionnalité permettant d’appeler Lisette depuis Go, mais la priorité est de permettre à Lisette d’importer des packages Go.
      Au départ, c’était une expérimentation, mais l’objectif est d’en faire un langage de niveau production.
  • Je me demande pourquoi ils n’ont pas repris telle quelle une syntaxe plus proche de Rust.
    Par exemple : import "foo.bar" au lieu de use foo::bar, Bar.Baz => au lieu de Bar::Baz =>, etc.
    Quelqu’un qui connaît Rust risque d’être perturbé, et quelqu’un qui ne le connaît pas n’en retirera pas de connaissances transférables vers Rust.

    • Ces différences de syntaxe sont mineures ; l’essentiel, c’est d’introduire le système de types de Rust dans Go.
      int et float64 suivent simplement les conventions de nommage des types de Go.
    • Quand on passe d’un langage à l’autre, les ressemblances syntaxiques peuvent au contraire créer de la confusion. Par exemple, j’oublie souvent qu’en PHP il faut utiliser . au lieu de +.
    • Moi aussi, j’ai d’abord voulu créer un langage au style Rust basé sur TypeScript, avant de réaliser que Rust lui-même n’est finalement pas si difficile.
    • Implémenter un modèle mémoire à la Rust dans un langage à GC est très peu naturel. C’est comme si chaque objet avait son propre espace d’adressage, ce qui complique tout.
    • Lisette est un langage inspiré par Rust, pas une tentative de devenir Rust. Sa cible principale, ce sont les développeurs Go.
  • Le runtime Go est bon, mais le langage lui-même est rustique et semble peu ouvert à l’amélioration.
    Donc, si on en vient à utiliser un transpileur, c’est qu’on doit vraiment ne pas aimer Go.

  • Je me demande pourquoi Rust et les langages de la même famille séparent les struct et les méthodes.
    Pourquoi ne peut-on pas définir directement les méthodes à l’intérieur de la struct ?

    • En Rust, les champs d’une struct influencent les auto-traits, donc il est important de voir les champs d’un seul coup d’œil.
      De plus, les blocs impl peuvent avoir des contraintes génériques différentes de celles de la struct, ce qui permet d’en définir plusieurs.
      Enfin, Rust est un langage conçu pour raisonner d’abord en fonction de la forme (Shape) des données.
    • Personnellement, j’ai l’impression que les blocs impl ressemblent aux méthodes de Go, et je ne dirais pas qu’une approche est clairement meilleure que l’autre.
  • S’il existait un langage à l’apparence de Python mais compilé en Rust ou en Go, ce serait vraiment génial.

    • Mojo est un langage haute performance basé sur une syntaxe proche de Python, créé par le fondateur de Swift.
    • Spy est une tentative précoce compilée en C, et Nim est aussi un langage mature dans cette veine.
    • Nim a une syntaxe proche de Python avec un système de types statique, et compile vers plusieurs cibles comme wasm et C.
    • Static Python Skill est une tentative de compilation statique de Python.
    • Grumpy était un transpileur Python→Go créé par Google, mais n’a pas été mis à jour depuis 9 ans (ciblait Python 2.7).
  • Lisette semble être un langage qui trouve bien l’équilibre entre la simplicité de Go et la complexité de Rust.
    Je me demande s’il y a une raison pour laquelle la compilation serait beaucoup plus lente qu’en Go, et quelles fonctionnalités de Rust ont été volontairement laissées de côté.
    Par exemple : borrow checking, types de données, async, etc.

  • Go est un langage facile à apprendre mais pauvre en fonctionnalités.
    Lisette semble intéressant comme langage qui comble ce manque.
    Comme TypeScript a étendu JavaScript, ajouter à Go un système de types expressif et un compilateur strict en ferait un excellent langage backend.
    Ma suggestion personnelle serait de prendre en charge le partage de types avec un frontend TypeScript. C’est aussi l’une des raisons pour lesquelles TypeScript est populaire côté backend.

  • En tant que développeur d’automatisation d’infrastructure partagé entre la sûreté de Rust et la simplicité de Go, l’idée de superposer l’ergonomie de Rust sur le runtime Go me paraît extrêmement séduisante.
    Je vais continuer à suivre l’évolution du projet.