Lisette — un petit langage compilé vers le runtime Go à partir d’une syntaxe inspirée de Rust
(lisette.run)- 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
tryet la concurrence basée surtaskassurent 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 commefmt,ioouosvia import
Une syntaxe familière
- Il adopte une structure syntaxique proche de Rust
- prise en charge du pattern matching via
enumetmatch - définition de méthodes possible avec des blocs
structetimpl
- prise en charge du pattern matching via
- C’est un langage orienté expressions :
if,letet 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
interfaceet écriture de fonctions génériques via des contraintesT: 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
nilest 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
- une erreur est produite si tous les motifs ne sont pas couverts dans une instruction
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
trysimplifient la propagation des erreurs - La concurrence s’appuie sur
tasketChannel, 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
recoverest fourni pour la récupération aprèspanic, avec un traitement sûr des erreurs via le typeResult - La syntaxe
deferest 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
OptionetResultsont respectivement transformés en structureslisette.Optionetlisette.Result - les instructions
matchsont converties en conditions Go traitant chaque branche - l’opérateur
?est remplacé en interne par du code de vérification deResult
- les types
- À titre d’exemple, la fonction
classifyreçoit unOption<int>puis est convertie en conditions Go explicites, tandis que la fonctioncombinedevient du code Go qui vérifieResult
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
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 nillié 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
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.
Go convient aussi très bien pour créer rapidement des outils CLI — par exemple : wordle-tui
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
deferde Go est utile, mais la gestion des erreurs et les règles de portée restent maladroites.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
Il existe déjà plusieurs langages qui compilent vers Go — XGo, Borgo, Soppo, etc.
(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.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.
lis run --debug, des commentaires//line source.lis:21:5sont 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 deuse foo::bar,Bar.Baz =>au lieu deBar::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.
intetfloat64suivent simplement les conventions de nommage des types de Go..au lieu de+.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 ?
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.
S’il existait un langage à l’apparence de Python mais compilé en Rust ou en Go, ce serait vraiment génial.
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.