Back to flin
flin

Le bug de gestion du None

Comment le modèle temporel de FLIN était bloqué par une correction de 10 lignes -- l'accès aux propriétés sur les valeurs None lançait des erreurs au lieu de se propager gracieusement.

Thales & Claude | March 30, 2026 3 min flin
EN/ FR/ ES
flinbugnonenull-safetytype-systemdebugging

Certains bugs bloquent des fonctionnalités entières. Ils siègent à un point d'étranglement dans l'architecture du système, et tant qu'ils ne sont pas résolus, tout en aval reste inutilisable. Le bug de gestion du None était l'un de ceux-là. Il était petit -- dix lignes de code pour le corriger -- mais il se tenait entre nous et le modèle temporel tout entier.

Le 7 janvier 2026, nous avions 27 tests d'intégration temporels. Tous les 27 échouaient. L'opérateur d'accès temporel (@) avait été implémenté. Le stockage de l'historique des versions fonctionnait. La base de données maintenait correctement les versions des entités. Mais au moment où vous tentiez d'utiliser quoi que ce soit en vrai code, la VM lançait un TypeError et s'arrêtait.

Le problème

L'opérateur @ de FLIN avec un offset négatif récupère les versions antérieures. Quand une seule version existe, user @ -1 retourne correctement None. Le bug se manifestait quand on tentait d'accéder à une propriété sur cette valeur None :

flinprevious = user @ -1           // Returns None (only 1 version exists)
<div>{previous.name}</div>     // TypeError: expected object, found none

La correction

La correction était remarquablement simple. Nous avons modifié deux opcodes dans la VM : GetField et GetFieldDyn.

rust// OpCode::GetField (src/vm/vm.rs:1484-1494)
if let Value::Object(id) = obj {
    // Normal path: access field on object
    self.push(value)?;
} else if obj == Value::None {
    // NEW: Propagate None instead of throwing error
    self.push(Value::None)?;
} else {
    return Err(RuntimeError::TypeError {
        expected: "object or none",
        found: obj.type_name().to_string(),
    });
}

Après la correction, None.property retourne None, permettant des chaînes d'accès temporel propres sans vérifications null verbeuses.

La décision de conception

Nous avons choisi la propagation implicite du None -- None.property retourne None. Cela reflète le chaînage optionnel de JavaScript (null?.property), la navigation sûre de TypeScript, et le Option::and_then() de Rust.

Le compromis est que la propagation du None peut masquer des bugs. Mais nous avons accepté ce compromis car le vérificateur de types de FLIN attrape les erreurs de noms de champs à la compilation. La propagation du None n'affecte que les valeurs à l'exécution qui sont légitimement None.

Impact sur le modèle temporel

La correction de 10 lignes a débloqué 27 tests d'intégration, dont 4 ont immédiatement commencé à passer. Les 23 restants étaient bloqués par un problème séparé de rendu des espaces blancs HTML, pas par des erreurs de logique temporelle.

Dix lignes de code. Une heure de travail. Tout un sous-système de fonctionnalités débloqué. Parfois la chose la plus précieuse qu'un développeur puisse faire n'est pas de construire quelque chose de nouveau, mais de supprimer un seul obstacle qui empêchait tout le reste de fonctionner.


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

Navigation de la série : - [157] Le bug d'itération de la boucle for - [158] Le bug de gestion du None (vous êtes ici) - [159] Le bug de rendu des espaces blancs HTML

Share this article:

Responses

Write a response
0/2000
Loading responses...

Related Articles