• [^] # Re: ~~Prem's~~

    Posté par . En réponse au lien Cloudflare : incident du 18-nov post mortem (un vilain unwrap en Rust). Évalué à 3. Dernière modification le 21 novembre 2025 à 17:31.

    les cRUSTacés vont t’expliquer que malgré les bogues qu’ils créent ils sont automagiquement plus sûr parce-que c’est comme ça

    Et pourtant, ils le sont (plus sûrs) !

    Là, c'est un exemple typique de ce que j'expliquais quand je disais que les programmeurs faisaient de l'axiomatique sans le savoir (API, c'est Axiomatique Pour Informaticien).

    Le type Result <T,E> est l'équivalent logique d'une disjonction : on a un résultat de type T ou une erreur de type E. L'axiomatique minimale et complète pour ce type est celle-ci :

    val ok : 't -> ('t,'e) Result
    val error : 'e -> ('t, 'e) Result
    val fold : ('ok -> 'res) -> ('err -> 'res) -> ('ok, 'err) Result -> 'res

    J'ai utilisé la syntaxe OCaml que je maîtrise mieux. Mais l'idée est qu'avec seulement ces 3 fonctions on peut implémenter toute l'API du type Result. Par exemple, le trait unwrap incriminé s'implémente ainsi :

    unwrap self = fold id panic self

    id est la fonction identité qui renvoie son argument et panic c'est ce qui est arrivé en cas d'erreur.

    Que ces trois fonctions suffisent, on le doit à Gödel (théorème de complétude) et Gentzen (déduction naturelle). Le type de ces trois fonctions correspondent aux règles de la déduction naturelle pour la disjonction : les deux premières sont les règles d'introduction de la disjonction (comment produire un Result) et la troisième à la règle d'élimination (comment consommer un Result).

    Ce qu'il y a, c'est que unwrap, qui de fait appel panic, ne doit être utiliser que sur des erreurs irrécupérables ! Il est peu probable que ce soit le cas ici, et unwrap n'aurait jamais du se trouver dans le code. C'est un bug de gestion d'erreurs, comme un exception non rattrapée mais qui aurait du l'être.

    Un programmeur C aurait pu faire de même :

    if (ptr == NULL) { exit };
    /* on peut déréférencer le ponteur dans la suite */

    mais là où unwrap apporte tout de même une sécurité mémoire, c'est qu'il ne déréférencera jamais un pointeur NULL, là où un programmeur C peut oublier d'écrire le test. La fonction fold (règle d'élimination, règle d'usage) exige un traitement pour le cas des erreurs, traitement qui dans le cas de unwrap est un panic. Cette exigence n'existe ni en C, ni en C++. ;-)

    Le cas des pointeurs est en fait équivalent au type Option, qui lui-même est équivalent au type Result où le type E des erreurs est un singleton.

    Après, si tu regardes les règles sur l'absurde sur la page wikipdéia (ce qui se passe ici, il y a une erreur parce que l'entrée est contradictoire avec les conditions dont à besoin la fonction pour avoir un résultat), en réfléchissant un peu tu pourras te convaincre que les règles la concernant correspondent au fonctionnement des exceptions (en particulier le raisonnement par l'absurde qui décharge l'hypothèse, c'est lever un exception avec sa backtrace : la série de raisonnement qui ont mener à la contradiction).

    Mais pour gérer les exceptions avec le type Result, il faut utiliser le ? en Rust. C'est la façon idiomatique d'utiliser ce que les programmeurs fonctionnels appellent le bind :

    bind v f = fold f error v

    Autrement dit on applique le traitement f en cas de succès et on fait remonter les erreurs à l'appelant, charge à lui de gérer l'erreur (si possible sans panic).

    Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.