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 noneLa 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