Il existe de nombreuses philosophies dans différentes disciplines du génie logiciel sur la façon dont les bibliothèques doivent faire face aux erreurs ou à d'autres conditions exceptionnelles. Quelques-uns de ceux que j'ai vus:
- Renvoie un code d'erreur avec le résultat renvoyé par un argument pointeur. C'est ce que fait PETSc.
- Renvoie les erreurs par une valeur sentinelle. Par exemple, malloc retourne NULL s'il ne peut pas allouer de mémoire,
sqrt
retournera NaN si vous passez un nombre négatif, etc. Cette approche est utilisée dans de nombreuses fonctions libc. - Jetez des exceptions. Utilisé dans deal.II, Trilinos, etc.
- Renvoie un type de variante; par exemple, une fonction C ++ qui renvoie un objet de type
Result
s'il s'exécute correctement et utilise un typeError
pour décrire comment il échouerastd::variant<Error, Result>
. - Utilisez assert et crash. Utilisé dans p4est et certaines parties d'igraph.
Problèmes avec chaque approche:
- La vérification de chaque erreur introduit beaucoup de code supplémentaire. Les valeurs dans lesquelles un résultat sera stocké doivent toujours être déclarées en premier, introduisant de nombreuses variables temporaires qui ne peuvent être utilisées qu'une seule fois. Cette approche explique quelle erreur s'est produite, mais il peut être difficile de déterminer pourquoi ou, pour une pile d'appels profonds, où.
- Le cas d'erreur est facile à ignorer. En plus de cela, de nombreuses fonctions ne peuvent même pas avoir de valeur sentinelle significative si toute la gamme de types de sortie est un résultat plausible. Beaucoup des mêmes problèmes que # 1.
- Uniquement possible en C ++, Python, etc., pas en C ou en Fortran. Peut être imité en C en utilisant la sorcellerie setjmp / longjmp ou libunwind .
- Uniquement possible en C ++, Rust, OCaml, etc., pas en C ou en Fortran. Peut être imité en C en utilisant la macro sorcellerie.
- Sans doute le plus informatif. Mais si vous adoptez cette approche pour, disons, une bibliothèque C pour laquelle vous écrivez ensuite un wrapper Python, une erreur idiote comme passer un index hors limites à un tableau plantera l'interpréteur Python.
Une grande partie des conseils sur Internet concernant la gestion des erreurs est écrite du point de vue des systèmes d'exploitation, du développement intégré ou des applications Web. Les accidents sont inacceptables et vous devez vous soucier de la sécurité. Les applications scientifiques n'ont pas ces problèmes à peu près dans la même mesure, voire pas du tout.
Une autre considération est de savoir quels types d'erreurs sont récupérables ou non. Un échec de malloc n'est pas récupérable et, dans tous les cas, le tueur de mémoire insuffisante du système d'exploitation y parviendra avant vous. Un index hors limites pour une taille de tableau n'est pas récupérable non plus. Pour moi en tant qu'utilisateur, la meilleure chose qu'une bibliothèque puisse faire est de planter avec un message d'erreur informatif. D'autre part, l'échec, par exemple, d'un solveur linéaire itératif à converger pourrait être récupéré en utilisant un solveur à factorisation directe.
Comment les bibliothèques scientifiques doivent-elles signaler les erreurs et s'attendre à ce qu'elles soient traitées? Je réalise bien sûr que cela dépend de la langue dans laquelle la bibliothèque est implémentée. Mais pour autant que je sache, pour toute bibliothèque suffisamment utile, les gens voudront l'appeler à partir d'une autre langue que celle dans laquelle elle est implémentée.
Soit dit en passant, je pense que l'approche # 5 peut être considérablement améliorée pour une bibliothèque C si elle définit un pointeur de fonction de gestionnaire d'assertion global dans le cadre de l'API publique. Par défaut, le gestionnaire d'assertion signale le numéro de fichier / ligne et se bloque. Les liaisons C ++ pour cette bibliothèque définiraient un nouveau gestionnaire d'assertion qui lève à la place une exception C ++. De même, les liaisons Python définiraient un gestionnaire d'assertion qui utilise l'API CPython pour lever une exception Python. Mais je ne connais aucun exemple qui adopte cette approche.