- La répétition de
if err != nil en Go reste l’une des principales frustrations dans les enquêtes utilisateurs depuis des années, mais l’équipe Go a décidé de ne pas faire avancer, pour l’instant, de changement syntaxique pour la gestion des erreurs
- Les propositions
check/handle en 2018, try en 2019 et ? en 2024 n’ont jamais obtenu un consensus suffisant ; try, en particulier, a suscité une forte opposition à cause d’un flux de contrôle implicite
- Dans le processus de proposition de Go, lorsqu’il n’y a pas de consensus général, une proposition est en général rejetée, et même parmi les membres les plus expérimentés de l’équipe Go chez Google, il n’existe pas aujourd’hui d’unanimité sur la meilleure direction à suivre
- Les partisans du statu quo estiment que Go dispose déjà d’une méthode de gestion des erreurs qui fonctionne, et qu’une nouvelle syntaxe entraînerait des coûts importants en matière de style de code, de débogage, de documentation, d’outillage et de code existant
- L’équipe Go va clore, sans investigation supplémentaire, les propositions ouvertes et nouvelles ayant principalement pour objet la syntaxe de gestion des erreurs, et se concentrer sur d’autres pistes d’amélioration jusqu’à ce qu’une compréhension plus claire du problème émerge
Une vieille frustration autour de if err != nil
- L’une des plaintes les plus persistantes à propos de Go est la verbosité du code de gestion des erreurs
- Le motif typique ressemble à ceci
x, err := call()
if err != nil {
// handle err
}
- Dans les programmes qui multiplient les appels d’API et se contentent souvent de renvoyer l’erreur,
if err != nil peut finir par dominer le reste du code
- Dans la fonction d’exemple
printSum, sur 10 lignes de corps de fonction, seules 4 lignes ressemblent à un véritable travail — appel, affichage et retour inclus — tandis que les 6 autres peuvent apparaître comme du bruit
- Dans l’enquête annuelle auprès des utilisateurs de Go, la gestion des erreurs figure depuis des années parmi les principales frustrations ; pendant un temps, l’absence de generics passait devant, mais depuis que Go les prend en charge, la gestion des erreurs est redevenue la plainte numéro un
Trois grandes propositions de syntaxe
- La première tentative explicite de l’équipe Go a commencé en 2018, dans le cadre des travaux sur Go 2, lorsque Russ Cox a formalisé le problème
- Le brouillon de conception de Marcel van Lohuizen reposait sur les mécanismes
check et handle, tout en analysant aussi les approches d’autres langages et plusieurs alternatives
func printSum(a, b string) error {
handle err { return err }
x := check strconv.Atoi(a)
y := check strconv.Atoi(b)
fmt.Println("result:", x + y)
return nil
}
- L’approche
check/handle a été jugée trop complexe, ce qui a conduit en 2019 à une proposition plus simple, try
- Le mot-clé proche de
check devenait la fonction intégrée try
- La partie
handle disparaissait
- Un outil, tryhard, a été créé pour convertir le code de gestion d’erreurs existant vers le style
try
- L’issue GitHub associée a donné lieu à un débat intense, avec près de 900 commentaires
func printSum(a, b string) error {
// use a defer statement to augment errors before returning
x := try(strconv.Atoi(a))
y := try(strconv.Atoi(b))
fmt.Println("result:", x + y)
return nil
}
try influait sur le flux de contrôle en provoquant un retour depuis la fonction englobante lorsqu’une erreur survenait, et comme ce retour pouvait aussi se produire dans des expressions profondément imbriquées, beaucoup d’utilisateurs ont eu du mal à l’accepter
- À l’époque, il aurait peut-être mieux valu introduire un nouveau mot-clé ; aujourd’hui, la version du langage peut être contrôlée finement via le fichier
go.mod et des directives par fichier
- La proposition récente de Jimmy Frasche revient à la conception d’origine
check/handle tout en tentant d’en corriger certains défauts
Retour sur le processus après try et proposition autour de ?
- Après la proposition
try, Russ Cox est revenu sur le processus de proposition à travers la série “Thinking about the Go Proposal Process”
- Dans “Go Proposal Process: Large Changes”, il estime que
try aurait dû être un deuxième brouillon de conception, et non une proposition avec un calendrier d’implémentation
- Pendant les années suivantes, l’équipe Go n’a plus poussé de changement syntaxique sur la gestion des erreurs, tandis que la communauté continuait à soumettre des propositions similaires, intéressantes, difficiles à comprendre ou irréalisables
- Ian Lance Taylor a créé une umbrella issue pour récapituler l’état des propositions d’amélioration de la gestion des erreurs, ainsi qu’une page du Go Wiki pour rassembler les retours et discussions associées
- “go error handling proposals” de Sean K. H. Liao suit de nombreuses propositions de gestion des erreurs accumulées au fil des ans
- Face à la persistance du mécontentement, Ian Lance Taylor a présenté en 2024 une proposition visant à réduire le boilerplate de gestion des erreurs avec
?
- La notation était empruntée à l’opérateur
? de Rust
- Dans une petite étude utilisateur informelle, la plupart des participants devinaient correctement la signification du code Go utilisant
?
- Un outil de conversion de code Go courant vers cette nouvelle syntaxe, ainsi qu’un prototype de compilateur, ont aussi été réalisés
func printSum(a, b string) error {
x := strconv.Atoi(a) ?
y := strconv.Atoi(b) ?
fmt.Println("result:", x + y)
return nil
}
- Cette proposition a elle aussi été rapidement submergée de commentaires et de suggestions de modifications fondées sur des préférences individuelles ; Ian a fini par la clore puis déplacer les échanges vers une discussion
- Une version légèrement révisée a reçu un accueil un peu plus favorable, sans pour autant obtenir un soutien large
Pourquoi l’équipe veut s’arrêter pour l’instant
- L’équipe Go considère qu’elle doit cesser, dans un avenir prévisible, de tenter de résoudre le problème syntaxique de la gestion des erreurs
- Le processus de proposition appuie cette décision
- Son objectif est d’aboutir, dans des délais raisonnables, à un consensus général sur un résultat
- Lorsqu’aucun consensus général n’émerge dans les discussions de l’issue tracker, la proposition est en général rejetée
- Si aucun consensus ni aucune suite claire n’apparaît, les architects de Go examinent alors la discussion et tentent de construire un consensus en interne
- Aucune proposition liée à la gestion des erreurs n’a obtenu un soutien proche du consensus, et toutes ont été rejetées
- Même parmi les membres les plus chevronnés de l’équipe Go chez Google, il n’existe pas d’unanimité sur la meilleure marche à suivre, et sans accord solide, il n’est pas raisonnable d’avancer
Les arguments pour le statu quo et pour le changement
- Le camp du statu quo avance des raisons pragmatiques liées à la maturité de Go et aux coûts pour l’écosystème
- Si Go avait introduit très tôt du sucre syntaxique dédié à la gestion des erreurs, le débat serait peut-être moindre aujourd’hui ; mais Go a maintenant 15 ans et dispose déjà d’une méthode qui fonctionne
- Même en trouvant aujourd’hui une solution parfaite, on pourrait simplement déplacer l’insatisfaction des partisans du changement vers ceux qui préfèrent le statu quo
- Les generics peuvent rester facultatifs pour de nombreux utilisateurs, mais une nouvelle syntaxe de gestion des erreurs risquerait de rendre le code non idiomatique si on ne l’utilise pas, ce qui obligerait de fait presque tout le monde à l’adopter
- Ajouter une nouvelle syntaxe peut aussi entrer en conflit avec le principe de conception de Go consistant à ne pas proposer plusieurs façons de faire la même chose
- La capacité de redéclaration dans la déclaration courte de variable
:= a été introduite pour résoudre un problème né de la gestion des erreurs
- Sans redéclaration, chaque vérification d’erreur successive aurait nécessité des noms
err différents ou des déclarations séparées
- Si un meilleur support syntaxique de la gestion des erreurs avait existé à l’époque, cette règle de redéclaration — et la complexité associée — n’aurait peut-être pas été nécessaire
- Lorsqu’on enrichit correctement les erreurs avant de les traiter, la part de répétition pure diminue
- Les enquêtes utilisateurs reviennent souvent sur l’absence de stack trace dans les erreurs
- Il est possible de renvoyer des erreurs enrichies via des fonctions utilitaires
- En ajoutant des informations d’entrée comme dans
fmt.Errorf("invalid integer: %q", a), la part relative du boilerplate devient moins importante
- Les fonctionnalités de la bibliothèque standard peuvent aussi réduire le boilerplate de gestion des erreurs
- Cela va dans le même sens que “Errors are values” de Rob Pike
- Dans certains cas,
cmp.Or permet de traiter plusieurs erreurs d’un coup
- Écrire, lire et déboguer sont des activités différentes
- Écrire des vérifications d’erreur répétitives est fastidieux, mais l’autocomplétion assistée par IDE et LLM peut générer facilement ces vérifications de base
- À la lecture, la verbosité saute davantage aux yeux, mais un IDE pourrait proposer un bouton pour masquer le code de gestion des erreurs
- En phase de débogage, la présence d’un
if distinct facilite déjà l’ajout de println ou la pose de points d’arrêt
- Si la gestion des erreurs est dissimulée derrière
check, try ou ?, il peut être nécessaire de revenir à un if, ce qui risque de compliquer le débogage ou d’introduire des bugs subtils
- Un changement de langage implique des coûts qui vont au-delà de la conception et de l’implémentation : adaptation du code existant, mise à jour de la documentation et ajustements des outils
- L’équipe Go est relativement petite et doit aussi gérer de nombreuses autres priorités
- Les priorités comme la taille de l’équipe peuvent toutefois évoluer
- Parmi certains utilisateurs de Go rencontrés par l’équipe Go à Google Cloud Next 2025, plusieurs ont exprimé fermement qu’il ne fallait pas modifier le langage pour améliorer la gestion des erreurs
- Selon eux, l’absence de syntaxe dédiée est surtout frappante lorsqu’on arrive d’un autre langage, mais devient moins importante à mesure qu’on écrit du Go plus idiomatique
- Cet échantillon n’est pas assez large pour être représentatif, mais il peut correspondre à une population différente de celle observée sur GitHub
- Les arguments en faveur du changement restent néanmoins valables
- L’absence d’un meilleur support pour la gestion des erreurs demeure la principale frustration dans les enquêtes utilisateurs
- Une approche focalisée uniquement sur la réduction du nombre de caractères est peut-être une fausse piste
- Si la gestion d’erreur par défaut devenait bien visible grâce à un mot-clé tout en supprimant le boilerplate
err != nil, il serait peut-être plus facile, en revue de code, de vérifier qu’une erreur est bien prise en compte
- On ne sait toujours pas assez clairement si le cœur du problème est la simple verbosité syntaxique, ou la verbosité d’une bonne gestion des erreurs — celle qui construit des erreurs porteuses de sens pour les développeurs comme pour les utilisateurs finaux
Décision de l’équipe Go
- Jusqu’à présent, aucune tentative de traiter la gestion des erreurs n’a obtenu un élan suffisant
- L’équipe Go estime qu’il manque une compréhension commune du problème, et que tout le monde n’est même pas d’accord sur l’existence même d’un problème
- Dans un avenir prévisible, elle ne poussera pas de changement syntaxique du langage pour la gestion des erreurs
- Les propositions ouvertes et futures ayant principalement pour objet la syntaxe de gestion des erreurs seront closes sans investigation supplémentaire
- Même si l’exploration et les discussions de la communauté n’ont pas débouché sur un changement syntaxique de la gestion des erreurs, elles ont conduit à plusieurs améliorations du langage Go et de son processus
1 commentaires
Avis sur Hacker News
Si l’on veut lancer à la légère des suggestions du genre « l’équipe Go aurait dû faire comme ça », il faudrait d’abord consulter la page wiki liée dans l’article https://go.dev/wiki/Go2ErrorHandlingFeedback et la recherche d’issues GitHub https://github.com/golang/go/issues?q=+is%3Aissue+label%3Aerror-handling
Ce que vous vous apprêtez à proposer n’est presque certainement pas inédit, et il est très probable qu’une bonne partie ait déjà été examinée en profondeur
J’apprécie cette approche franche de l’équipe Go, et j’utilise toujours Go avec plaisir tous les jours au travail
Je n’ai rien vu de similaire non plus dans les quelques pages d’issues GitHub les plus commentées, et il me paraît difficile de supposer que l’équipe Go, parce qu’elle serait composée de magiciens de la conception de langages, a forcément étudié les solutions que les gens ici lancent à la légère
L’équipe Go a commis la même erreur que Java, à savoir avoir un typage statique sans polymorphisme paramétrique, et c’est aussi la racine de ce problème de gestion des erreurs ; on a l’impression qu’elle baisse les bras et refuse de le corriger
Cela peut sembler grandiloquent et intimidant, mais c’est une manière élégante et fonctionnellement pure de propager les erreurs jusqu’à l’endroit où elles peuvent être traitées, tout en évitant qu’elles soient oubliées
Pour les gens qui écrivent du code Haskell, c’est une approche tellement ancrée qu’il est difficile de comprendre qu’il n’y ait eu personne dans la communauté Go pour la connaître et l’apprécier
Merci pour la page elle-même et les liens, mais il est déconcertant que des personnes qui se soucient autant de leur langage soient passées à côté d’une solution aussi bien établie
Presque tous les langages ont chacun une meilleure approche ; j’aimerais savoir si c’est simplement qu’ils n’arrivent pas à trancher ou à satisfaire tout le monde, ou s’il existe des raisons concrètes, propres à Go, pour lesquelles les solutions des autres langages ne conviennent pas
En réalité, dans presque tous les cas, ils en savent beaucoup plus
Les amateurs pensent naïvement que le meilleur langage est celui dans lequel on a entassé le plus de fonctionnalités, surtout quand il contient celles qui correspondent à leurs préférences
C’est un peu comme quelqu’un qui débute dans la fabrication de couteaux, regarde un couteau de chef japonais et le trouve insuffisant, puis se dit qu’il serait meilleur avec un manche imprimé en 3D doté d’empreintes pour les doigts, d’un compartiment secret, d’un briquet et d’une enceinte Bluetooth
Il suffirait de créer une checklist, de discuter chaque point et de les cocher, puis de ne plus les retirer sauf si l’on découvre une erreur sémantique fatale ou une faille de sûreté
Une fois tout rempli, on implémente, et ceux qui débattaient pour savoir s’il faut écrire
.await,/awaitou.await!()disparaîtront à nouveauRust fonctionne comme ça ; certaines issues peuvent être retardées pendant plus de dix ans, mais les points finissent par être cochés et stabilisés depuis la nightly la plus récente
Si Go n’arrive pas à résoudre un unique problème auquel tout le monde se heurte immédiatement, alors qu’il existe plusieurs propositions très abouties, simplement parce qu’il n’arrive pas à en choisir une et attend que le bikeshedding cesse, alors son processus est une farce
Ce n’est pas une collection de fonctionnalités que l’on ajoute simplement parce qu’elles satisfont des cases à cocher
Rust sera-t-il devenu un bazar comme C++ ? Go sera-t-il resté un langage intemporel, comme au moment de sa sortie ?
Dans l’enquête, la proportion de personnes ayant mentionné la gestion des erreurs était de 13 %, et certaines préfèrent la manière actuelle
https://go.dev/blog/survey2024-h1-results
J’ai déjà écrit une fonction Go un peu particulière, qui s’attendait à ce qu’une fonction interne renvoie une erreur.
Donc si la fonction interne ne renvoyait pas d’erreur, la fonction externe devait renvoyer une erreur et faire autre chose ; si la fonction interne renvoyait une erreur, elle devait renvoyer nil.
En résumé, il fallait écrire non pas
if err != nil { ... }, maisif err == nil { // return an error }. Par habitude, j’ai écrit le premier, et le débogage m’a pris pas mal de temps.C’est parce que j’étais devenu tellement insensible à
if err != nilque mon cerveau n’a même pas envisagé que cette construction ne devait pas être là.C’est pourquoi je pense que les expressions courantes ont besoin de sucre syntaxique. Si la différence entre le très courant
if err != nilet le rareif err == nilavait été plus visible, cela m’aurait vraiment aidé.if err == nil, j’ajoute le commentaire// invertedpour le rendre plus visible.Ce serait bien que ce soit pris en charge au niveau du langage, mais je partage au moins cette façon de le rendre plus repérable.
if fruit != "Apple" { ... }peut créer exactement la même situation.Je me demande s’il existe une solution générale pour améliorer cela, et voir ça comme un problème propre à la gestion des erreurs me semble un peu à côté de la plaque.
Il n’y a rien de spécial ni d’unique dans les erreurs ; ce ne sont que des états comme les autres.
Si un motif courant
if err == nil { return ... }apparaît, il se retrouvera partout dans le code à son tour.La solution actuelle est correcte, et elle semble surtout déplaire aux gens qui débutent avec Go ou qui sont encore à un niveau débutant.
Autour de moi, les gens apprécient la gestion des erreurs « verbeuse », explicite, claire et facile à lire.
if err != nilcomme une seule petite ligature, ou l’afficher en arrière-plan de façon atténuée.Ainsi, toute forme différente de cette chaîne exacte, comme
if err == nil, ressortirait au contraire visuellement.if err … {.J’aime la gestion explicite des erreurs de Go.
Une fonction réussit toujours, ou bien elle peut réussir ou échouer. Une fonction qui réussit toujours est simple ; si une fonction susceptible d’échouer échoue, le code appelant ne peut pas continuer en état d’échec, donc il doit traiter le cas.
C’est là que les langages divergent. Beaucoup de langages lancent des exceptions, les font remonter jusqu’à ce que quelqu’un les attrape explicitement, et fournissent une sorte de trace de pile.
En Go, j’aime le fait qu’en écrivant le code, on ait toujours un choix à faire : ignorer l’erreur et continuer (
foo, _ := doSomething()), retourner tôt sans information significative (return nil, err), retourner tôt avec un contexte utile, ou interpréter l’erreur reçue pour bifurquer.Par exemple, si la base de données ne trouve pas la ligne à modifier, la couche service peut renvoyer une erreur not found qui devient un 404 côté API, ou bien une fonction de suppression idempotente peut interpréter not found comme un succès.
Dans Go 2 ou un autre langage, j’aimerais avoir, au lieu de tuples pouvant contenir nil, un type Result à la Rust/Swift, ainsi que des types d’erreur mieux typés et énumérables plutôt que d’utiliser toujours directement
error.Cela dit, ajouter Result par-dessus le retour de tuple idiomatique de Go 1 créerait plusieurs façons de faire la même chose, donc de la confusion et des divisions ; cela conviendrait mieux à Go 2 ou à un nouveau langage.
Les couches basses de la pile ne savent généralement pas quoi faire, donc elles ne devraient pas traiter les erreurs.
La politique consistant à traiter une erreur finit souvent par être une politique qui l’enveloppe et la renvoie vers le haut de la pile, ce qui devient beaucoup de travail fastidieux.
Go permet d’ignorer complètement les erreurs, ce qui peut mener à un crash.
Je ne comprends pas très bien comment on peut identifier exactement les exigences nécessaires pour construire un logiciel robuste et malgré tout aimer la façon dont Go gère les erreurs.
[1]: https://borgo-lang.github.io/ | https://github.com/borgo-lang/borgo
Tous les langages fonctionnels, beaucoup de langages modernes comme Rust, et même Java avec ses checked exceptions proposent cela.
Avec un langage doté de génériques, on peut globalement reproduire la « gestion des erreurs » façon Go, et probablement obtenir un meilleur code.
Si la réponse est JavaScript ou Python, c’est effectivement un schéma de comparaison courant.
Pour Go, c’est la bonne décision. Quand j’ai découvert Go, je n’aimais pas sa gestion des erreurs, mais aujourd’hui je l’apprécie vraiment.
Le déclic est venu de deux choses. En lisant l’article https://go.dev/blog/errors-are-values, j’ai vraiment adopté l’idée que « les erreurs sont des valeurs », et sur cette base j’ai aussi créé un package assez populaire, https://github.com/stytchauth/sqx.
Je me suis aussi habitué à utiliser petit à petit
panic(err)pour les états invalides vraiment absurdes.Il n’y a aucune raison de forcer le code parent à gérer tous les états incohérents dont il n’a aucune idée de quoi faire ; un ou deux panic bien placés peuvent supprimer des centaines de vérifications d’erreurs dans une base de code.
On peut par exemple penser à la question de savoir s’il y a un logger par défaut dans ctx.
Au contraire, il y a de fortes chances que cela s’améliore.
bash a aussi
-e.Quand j’ai commencé avec C# il y a longtemps, je trouvais intelligent de comprendre le flux try/catch/finally, using, l’imbrication, ce qui se passe si une erreur survient dans catch, ce qui se passe si elle survient dans finally.
Maintenant, je préfère ne pas avoir à penser à ce genre de choses.
Je n’aime pas la façon dont cet article présente le principal problème de la gestion des erreurs en Go comme étant une syntaxe trop verbeuse. Ce n’est pas vraiment ce qui me préoccupe
Le plus important, c’est que les erreurs peuvent être silencieusement jetées ou ignorées par accident, que le résultat d’un appel de fonction n’est pas une valeur qu’on peut facilement stocker ou transmettre, et que
errors.Isest nécessaire tout en étant un dispositif d’exécution étrange, où les erreurs « imbriquées » ne s’accordent pas vraiment avec le système de typesLes switch sur les erreurs sont aussi difficiles, la bibliothèque standard utilise des valeurs sentinelles, et l’interaction avec les génériques est mauvaise, ce qui rend nécessaires des packages comme errgroup
Qu’est-ce que j’oublie encore ?
Dans un langage avec exceptions, personne ne ferait ça
Il a été décidé de ne plus tenter de modifier la syntaxe de gestion des erreurs dans un avenir prévisible, ce qui libère de l’attention pour examiner d’autres problèmes, qu’ils concernent les erreurs ou d’autres sujets
L’évolution de Go est lente comme un glacier, et pour beaucoup de gens ce n’est pas un bug, c’est une feature
L’explication du type « les retours du sondage disant que les erreurs n’ont pas de stack trace peuvent être résolus en faisant en sorte qu’une fonction auxiliaire crée et retourne une erreur enrichie » est risible
C’est amusant d’appeler « gestion des erreurs » le fait de fournir manuellement une stack trace, comme dans
if err != nil { return fmt.Errorf("invalid integer: %q", a) }Selon la définition de l’équipe Go, les exceptions gèrent donc automatiquement les erreurs. Dans les langages autres que C++, bien sûr
Peut-être, mais a-t-on vraiment besoin de tout ça ? Et le coût des logs ?
Je trouve qu’une erreur enveloppée sur une ligne, qui coupe le bruit du framework et du runtime, est bien meilleure
Bien enveloppée, elle est aussi très facile à rechercher et, en général, elle permet de remonter la piste plus efficacement qu’une stack trace
En plus de dix ans d’utilisation de Go à plein temps, je n’ai jamais eu besoin du bruit verbeux des fonctions runtime ou de la pile d’appels
Du point de vue d’un développeur Elixir, ça a l’air complètement fou
En Erlang/Elixir, le problème se résout généralement en faisant retourner aux fonctions un tuple
{:ok, result}ou{:error, description_or_struct}En y ajoutant l’instruction
withd’Elixir, on peut regrouper la gestion des erreurs en bas, ce qui rend le code beaucoup plus lisibleGo pourrait aussi ajouter l’équivalent d’une clause
with, continuer à exécuter les fonctions tant que l’erreur est nil, puis placer la clause de gestion des erreurs en dessouswithIl est intéressant de voir que Go repousse pendant très longtemps des constructions fondamentales et manifestement utiles, comme les génériques, la gestion des erreurs ou la gestion des packages, à cause d’un manque de consensus dans la communauté
Les génériques ont mis 13 ans après l’ouverture en open source, 16 ans plus tard il n’y a toujours pas de gestion des erreurs, et la gestion des packages a pris environ 9 ans
La réflexion a de la valeur, mais livrer en a aussi. Les gens qui écrivent 900 commentaires GitHub continueront de toute façon à utiliser Go, et il est probable qu’intégrer quelque chose dans le langage aurait été préférable à repousser sans cesse
Une fonction qui a plusieurs types de retour ne peut servir à rien d’autre qu’à affecter des variables
Mais en Erlang et Elixir, c’est une pratique parfaitement idiomatique, sans aucun poids supplémentaire
En réalité, c’est même bien plus puissant que dans la famille ML, parce que leurs types somme sont ouverts
Je n’ai pas suivi cette discussion en détail, mais je ne comprends pas pourquoi ils n’adoptent pas simplement l’approche à la Rust
C’est aussi celle que j’ajoute immédiatement depuis que Go a des génériques
Dans l’article lié, je ne vois que l’explication selon laquelle « Rust n’a rien qui corresponde à handle, et la commodité de l’opérateur
?peut inciter à omettre un traitement approprié »Mais je ne vois pas en quoi le fait que ce soit pratique signifierait qu’on ignore les erreurs
La moitié du problème de l’approche Go, c’est qu’elle n’impose rien sur le résultat et n’impose que le minimum en matière de vérification des erreurs
x, err := strconv.Atoi("123"); fmt.Println("result:", x)produitdeclared and not used: err, mais après une deuxième conversion, même si on ne vérifie paserr, la valeur par défaut 0 deypeut faire que tout s’exécute sans qu’on voie le problèmeMême
if err != nil { }, vide, compile et s’exécute, sans permettre de savoir que quelque chose ne va pasSi l’on fait de la valeur de retour un Result, on impose de prendre une décision. Même si quelqu’un abuse de
!ou remonte les erreurs facilement avec?sans traiter les cas d’erreur, va-t-on aussi interdirepanic?Et à cause de cette étrange obsession qui veut que tous les types aient une valeur zéro définie, il ne peut pas non plus ajouter de types somme
?est pratique à utiliser, plus personne n’enveloppera les erreursC’est une logique très douteuse
Il suffirait de concevoir
?de façon à encourager l’enveloppement des erreursPar exemple, à quoi devrait ressembler dans Go l’équivalent du
Fromde Rust ??est peu visible et masque une branche du flux de contrôle dans une instruction ou une expressionC’est aussi l’une des raisons pour lesquelles Go a supprimé l’opérateur ternaire et choisi des instructions
ifoù chaque branche est sur une ligne distincteIl n’est pas non plus facile d’y poser un point d’arrêt, et cela encourage à remonter l’erreur telle quelle plutôt qu’à l’enrichir ou à la traiter
:=était une déclaration et une affectation en une seule instruction, mais à la 5e ligne de l’exemple,errn’est-il pas redéclaré, le nouveauerrmasquant l’ancien ?Dans ce cas, la nouvelle variable
errn’étant pas utilisée, cela devrait échouer avecdeclared and not used: errOu bien, si la variable existe déjà,
:=se comporte-t-il simplement comme une affectation normale ?Dire que « l’absence de trace de pile dans les erreurs peut être résolue en faisant en sorte que les fonctions auxiliaires créent et renvoient des erreurs enrichies » est beaucoup trop optimiste par rapport à la réalité
Les langages qui ont des traces de pile vous donnent ça gratuitement, alors qu’en Go il faut l’implémenter à chaque fois
On peut être soi-même un développeur discipliné qui ajoute toujours des détails, mais tous les membres de l’équipe n’ont pas la même discipline
Le meilleur aspect d’une trace de pile, c’est qu’elle donne le chemin d’appel jusqu’à l’erreur
Quand une erreur se produit dans une méthode appelée depuis plusieurs endroits, la trace de pile permet de voir immédiatement quel chemin a été emprunté
Pendant des années, j’ai résolu beaucoup de problèmes dans un rôle proche de sysadmin/SRE, et lorsqu’il y avait une trace de pile, les problèmes faciles étaient réglés en 1 ou 2 minutes parce que la cause était évidente
En Go, si quelqu’un n’enrichit pas l’erreur ou réutilise le même message d’erreur, même un problème simple devient une enquête et prend plus de temps