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.

Juste A. Gnimavo (Thales) & Claude | March 26, 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

Thales & Claude deblo

Le Step Zero ne suffisait pas : comment valider un constructeur sans valider le runtime a fait tomber toutes les sessions vocales de Déblo l’heure où nous avons livré le streaming caméra temps réel

La phase 14 a livré Déblo Eyes — streaming caméra temps réel via LiveKit vers Gemini Live native audio. Le premier deploy a fait tomber toutes les sessions vocales en production en quatre-vingt-dix secondes parce que notre Step 0 avait validé le constructeur sans exercer le runtime. Le build log de comment Déblo a eu des yeux, ce qu’un pré-vol incomplet a coûté, et quels points de polish ont été livrés ou reportés.

33 min May 20, 2026
debloclaude-opus-4.7claude-codegemini-live +25
Thales & Claude deblo

Le tiret cadratin qui a tué la production : comment un slogan marketing dans un header HTTP a fait tomber le chat de Déblo pendant 24 heures

Deux jours avant la soumission App Store, tout le produit chat de Déblo s’est cassé silencieusement. Pas de spinner, pas de toast, aucune erreur dans l’UI — juste un silence radio. L’incident de 24 heures se résumait à un seul « é » dans la valeur d’un header HTTP qui levait une UnicodeEncodeError avant qu’aucune requête vers OpenRouter ne quitte le backend. Post-mortem d’une fausse hypothèse, d’une trace Sentry, et d’un fix de six lignes qui a débloqué le lancement.

30 min May 19, 2026
debloclaude-opus-4.7claude-codeincident +19
Thales & Claude deblo

Six heures, d’une page blanche à la review Apple — Comment nous avons soumis Déblo à l’App Store, en direct

Marche à marche en direct de la soumission de Déblo à l’App Store iOS en six heures : ce que les validateurs d’Apple ont rejeté (un superscript Unicode), ce que nous avons corrigé (un Promotional Text gaspillé sur des marques tierces), et les rouages de l’ASO iOS que presque tout le monde rate.

30 min May 13, 2026
debloclaude-opus-4.7claude-codeapp-store +16