Back to flin
flin

Le système de types de FLIN : inféré, expressif, sûr

Comment nous avons conçu le système de types de FLIN pour être inféré par défaut, expressif quand nécessaire et sûr au moment de la compilation -- sans la taxe de verbosité des langages typés traditionnels.

Thales & Claude | March 30, 2026 5 min flin
EN/ FR/ ES
flintype-systeminferencesafety

La plupart des langages de programmation forcent un choix. Vous pouvez avoir la sécurité, mais vous la payez avec des annotations de type sur chaque ligne. Ou vous pouvez avoir la brièveté, mais vous acceptez que des catégories entières de bogues ne se manifestent qu'à l'exécution, en production, à 3 heures du matin.

FLIN refuse le compromis.

Quand nous nous sommes assis pour concevoir le système de types de FLIN -- un langage destiné aux développeurs qui veulent construire des applications full-stack dans un seul fichier -- nous avons commencé par une question qui semble simple mais porte d'énormes conséquences : quelle est la quantité minimale d'informations de type qu'un développeur devrait avoir à écrire, étant donné que le compilateur peut déterminer le reste ?

La réponse est devenue la fondation de tout dans cet article : des types que vous écrivez rarement, une sécurité que vous obtenez toujours.

Les principes de conception

Quatre principes ont guidé chaque décision du système de types.

Inféré. Les types sont automatiquement déterminés à partir des valeurs. Si vous écrivez count = 42, le compilateur sait que c'est un int. Vous ne devriez pas avoir à le lui dire.

Simple. Un petit ensemble de types clairs et utiles. Pas de distinction entre i8, i16, i32, i64, u8, u16, u32, u64 comme en Rust. Pas de String versus &str versus &'a str. Un type entier. Un type virgule flottante. Un type texte.

Sûr. Attraper les erreurs au moment de la compilation, pas à l'exécution. Si vous essayez d'additionner un nombre et une valeur texte, le compilateur devrait vous le dire immédiatement, pas laisser l'application planter quand un utilisateur déclenche ce chemin de code six mois plus tard.

Pratique. Des types qui correspondent aux données du monde réel. Un type money qui comprend les devises. Un type time avec des mots-clés temporels. Un type semantic text qui génère automatiquement des embeddings IA.

Types primitifs

FLIN a quatre types primitifs :

flinname = "Juste"          // text -- chaîne UTF-8
count = 42              // int -- entier signé 64 bits
price = 99.99           // number -- virgule flottante 64 bits
active = true           // bool -- booléen

Pas d'annotations de type. Le compilateur infère chacun. Le développeur écrit la valeur ; le compilateur détermine le type.

Types spéciaux

Time

Le type time est un horodatage UTC avec précision nanoseconde, avec des mots-clés temporels : now, today, yesterday, tomorrow, last_week, last_month. Ces mots-clés ne sont pas des fonctions. Ce sont des valeurs.

Money

Le type money impose l'homogénéité des devises. Deux valeurs money ne peuvent participer à l'arithmétique que si elles partagent une devise. C'est une contrainte qui nécessiterait une validation à l'exécution dans la plupart des langages mais devient une garantie au moment de la compilation dans FLIN.

Semantic Text

Un champ semantic text est automatiquement embarqué dans une représentation vectorielle quand il est sauvegardé. Cela active la recherche par similarité vectorielle sans que le développeur ne touche jamais un modèle d'embedding.

Inférence de types

L'inférence de types dans FLIN est bidirectionnelle. L'information coule des valeurs vers les variables (inférence avant) et du contexte vers les expressions (inférence arrière).

Chaque opération d'entité a un type de retour connu. Entity.all retourne [Entity]. Entity.find(id) retourne Entity? -- un optionnel. Entity.count retourne int. Le compilateur propage ces types à travers chaque opération suivante sur le résultat.

Types optionnels

Tout type peut être rendu optionnel avec ?. FLIN élimine les exceptions de pointeur nul grâce à la propagation automatique de none et au rétrécissement de type :

flinuser: User? = User.find(id)
if user {
    // À l'intérieur de ce bloc : user est User (pas User?)
    print(user.name)    // sûr -- le compilateur sait que user n'est pas none
}

Messages d'erreur

Un système de types n'est aussi bon que ses messages d'erreur :

error[E0001]: type mismatch
  --> app.flin:12:15
   |
12 |     count = "hello"
   |             ^^^^^^^ expected int, found text
   |
   = note: count was declared as int on line 5
   = hint: use int("hello") to parse, or change count's type

Chaque message d'erreur a trois parties : ce qui s'est mal passé, où c'a été déclaré et quoi faire. L'indice suggère des corrections concrètes.

L'implémentation en Rust

Le système de types entier est implémenté en environ 4 000 lignes de Rust à travers trois fichiers. Le FlinType enum est la structure de données centrale avec des variantes pour Int, Number, Text, Bool, Time, Money, List, Map, Optional, Entity, Union, TypeParam, Generic, Enum, Never, Any et Unknown.


Ceci est la partie 31 de la série « Comment nous avons construit FLIN », documentant comment un CEO à Abidjan et un CTO IA ont conçu et implémenté un langage de programmation à partir de zéro.

Navigation de la série : - [31] Le système de types de FLIN : inféré, expressif, sûr (vous êtes ici) - [32] Types union et rétrécissement de type - [33] Types génériques dans FLIN - [34] Traits et interfaces - [35] Pattern matching : de switch à match

Share this article:

Responses

Write a response
0/2000
Loading responses...

Related Articles