Files
saselang-bible/chapters/028-defer-et-nettoyage.md
2026-09-13 10:20:16 +02:00

3.3 KiB

28. defer et nettoyage

28.1 defer — V1 REQUIS — FIGÉ

defer est lié au scope lexical dans lequel il est atteint. Il enregistre un cleanup exécuté à toute sortie de ce scope.

Exemple :

{
    acquireA();
    defer {
        releaseA();
    }

    acquireB();
    defer {
        releaseB();
    }

    work();
}

Les defer d'un même scope s'exécutent en ordre LIFO :

releaseB();
releaseA();

Un defer n'est actif que si son statement a réellement été atteint pendant l'exécution.

Les sorties qui déclenchent les defer du scope traversé comprennent notamment :

fin normale
return
throw
Fault propagé
break
continue
emit quittant le scope concerné

La valeur d'un return ou d'un emit est déterminée avant l'exécution des cleanups nécessaires ; les defer ne peuvent pas la remplacer.

28.2 Unwind et ordre avec catch / finally — V1 REQUIS — FIGÉ

Lorsqu'une Exception ou un Fault capturable quitte un scope, les defer des scopes abandonnés sont exécutés avant l'entrée dans le catch correspondant, sous réserve des détails d'unwind de Fault encore à fermer avec le runtime.

Ordre conceptuel :

throw / Fault propagé
-> unwind des scopes quittés
-> defer de ces scopes, LIFO
-> catch correspondant éventuel
-> defer du scope catch, LIFO
-> finally éventuel
-> continuation normale ou propagation

Chaque scope imbriqué possède sa propre pile LIFO et est entièrement déroulé avant de poursuivre le scope parent.

L'ordre exact entre defer et les futurs destructeurs automatiques sera finalisé avec le modèle mémoire/lifecycle, sans modifier la règle de scope LIFO propre à defer.

28.3 defer non-escaping — V1 REQUIS — FIGÉ

Comme finally, un bloc defer ne doit jamais remplacer une sortie déjà en cours.

Sont interdits dans un defer lorsqu'ils quittent le bloc :

return
throw
fault
break
continue
emit

Aucune Exception non capturée ne peut sortir indirectement d'un defer. Une callable appelée depuis un defer et susceptible de lancer une Exception doit voir cette exception entièrement gérée à l'intérieur du bloc defer.

Un fault explicite est interdit dans un defer pour la même raison qu'un throw explicite : le cleanup ne doit pas volontairement remplacer une sortie déjà en cours. Un Fault dynamique produit indirectement reste possible car il est unchecked ; son interaction exacte avec l'unwind/destruction fait partie du modèle mémoire encore à fermer.

Un ResultError reste une simple valeur : un appel retournant Result<T,E> est autorisé dans un defer, sous réserve des règles normales de traitement de cette valeur.

28.4 finally versus defer — V1 REQUIS — FIGÉ

defer sert au cleanup lexical lié à une acquisition ou à un scope local.

finally sert au bloc commun final d'une vraie construction try/catch.

Un try/finally sans catch est interdit précisément parce que defer couvre le besoin de cleanup systématique sans introduire une construction d'exception inutile.

28.5 errdefer — REJETÉ

Pas de errdefer séparé en V1.

catch gère les chemins d'Exception et de Fault; defer gère le cleanup systématique du scope. Un troisième mécanisme dédié uniquement à l'échec serait redondant.