GOTO toujours considéré comme nocif?

Tout le monde est au courant des lettres de Dijkstra à l’éditeur: allez à la déclaration considérée comme nuisible (aussi ici .html transcript et ici .pdf) et il y a eu une formidable pression depuis ce temps pour éviter la déclaration goto chaque fois que possible. Bien qu’il soit possible d’utiliser goto pour produire un code non extensible et tentant, il rest néanmoins dans les langages de programmation modernes . Même la structure de contrôle de continuation avancée de Scheme peut être décrite comme un goto sophistiqué.

Quelles circonstances justifient l’utilisation de goto? Quand est-il préférable d’éviter?

Pour répondre à cette question: C fournit une paire de fonctions, setjmp et longjmp, qui permettent de passer non seulement dans le cadre de la stack actuelle, mais dans l’une des images appelantes. Faut-il les considérer comme dangereux? Plus dangereux?


Dijkstra lui-même regrettait ce titre dont il n’était pas responsable. A la fin de EWD1308 (aussi ici .pdf) il a écrit:

Enfin une petite histoire pour le disque. En 1968, les communications de l’ACM ont publié un de mes textes intitulé ” La déclaration goto jugée nuisible “, qui serait mentionnée plus tard dans les années ultérieures, malheureusement, mais souvent par des auteurs qui n’en avaient jamais vu plus titre, qui est devenu la pierre angular de ma renommée en devenant un modèle: nous verrions toutes sortes d’articles sous le titre “X considéré comme dangereux” pour presque tous les X, y compris celui intitulé “Dijkstra considéré comme dangereux”. Mais que s’est-il passé? J’avais soumis un document intitulé ” Une affaire contre la déclaration goto “, qui, pour accélérer sa publication, avait été remplacé par une “lettre à l’éditeur” et, dans le processus, il lui avait donné une nouvelle titre de sa propre invention! L’éditeur était Niklaus Wirth.

Un article classique bien pensé sur ce sujet, à rapprocher de celui de Dijkstra, est la programmation structurée avec aller aux déclarations , par Donald E. Knuth. La lecture aide à rétablir le contexte et une compréhension non dogmatique du sujet. Dans cet article, l’avis de Dijkstra sur ce cas est rapporté et est encore plus fort:

Donald E. Knuth: Je pense qu’en présentant un tel sharepoint vue, je ne suis pas en désaccord avec les idées de Dijkstra, car il a récemment écrit ceci: “Ne tombez pas dans le piège de croire que je suis terriblement dogmatique aller à la déclaration]. J’ai le sentiment désagréable que d’autres en font une religion, comme si les problèmes conceptuels de la programmation pouvaient être résolus par une seule astuce, par une simple forme de discipline de codage!

Les déclarations suivantes sont des généralisations; Bien qu’il soit toujours possible de plaider des exceptions, cela ne vaut généralement pas les risques (à mon avis et à mon humble avis).

  1. L’utilisation sans contrainte des adresses mémoire (GOTO ou pointeurs bruts) offre trop d’opportunités pour faire des erreurs facilement évitables.
  2. Plus il y a de façons d’arriver à un “emplacement” particulier dans le code, moins on peut être sûr de l’état du système à ce stade. (Voir ci-dessous.)
  3. La programmation structurée IMHO consiste moins à «éviter les GOTOs» et plus à faire correspondre la structure du code à la structure des données. Par exemple, une structure de données répétée (par exemple, un tableau, un fichier séquentiel, etc.) est naturellement traitée par une unité de code répétée. Avoir des structures intégrées (par exemple, while, for, until, for-each, etc.) permet au programmeur d’éviter l’ennui de répéter les mêmes modèles de code clichés.
  4. Même si GOTO est un détail d’implémentation de bas niveau (pas toujours le cas!), Il est en dessous du niveau auquel le programmeur doit penser. Combien de programmeurs équilibrent leurs chéquiers personnels en binary brut? Combien de programmeurs s’inquiètent de savoir quel secteur du disque contient un enregistrement particulier, au lieu de simplement fournir une clé à un moteur de firebase database (et de combien de façons les choses pourraient-elles mal tourner si nous écrivions tous nos programmes en termes de secteurs de disque physique)?

Notes en bas de page:

En ce qui concerne le point 2, considérez le code suivant:

 a = b + 1 /* do something with a */ 

Au sharepoint “faire quelque chose” dans le code, on peut affirmer avec une confiance élevée que a est supérieur à b . (Oui, j’ignore la possibilité de débordement d’entier non piégé. Ne nous contentons pas d’un exemple simple.)

Par contre, si le code avait lu de cette manière:

 ... goto 10 ... a = b + 1 10: /* do something with a */ ... goto 10 ... 

La multiplicité des façons d’obtenir l’étiquette 10 signifie que nous devons travailler beaucoup plus fort pour avoir confiance dans les relations entre a et b à ce stade. (En fait, dans le cas général, c’est indécidable!)

En ce qui concerne le point 4, toute la notion de “se déplacer” dans le code n’est qu’une métaphore. Rien n’est vraiment “aller” n’importe où dans le CPU, sauf les électrons et les photons (pour la chaleur perdue). Parfois, nous abandonnons une métaphore pour une autre, plus utile. Je me souviens d’avoir rencontré (il y a quelques décennies!) Une langue où

 if (some condition) { action-1 } else { action-2 } 

a été implémenté sur une machine virtuelle en compilant les actions-1 et action-2 en tant que routines sans paramètre hors ligne, puis en utilisant un seul code opération VM à deux arguments utilisant la valeur booléenne de la condition pour appeler l’un ou l’autre. Le concept était simplement “choisir quoi invoquer maintenant” plutôt que “aller ici ou y aller”. Encore une fois, juste un changement de métaphore.

XKCD's GOTO Comic

Un de mes collègues a dit que la seule raison d’utiliser un GOTO est si vous vous êtes programmé si loin dans un coin que c’est la seule issue. En d’autres termes, une conception appropriée à l’avance et vous n’aurez pas besoin d’utiliser un GOTO plus tard.

Je pensais que cette bande dessinée illustre cela magnifiquement “Je pourrais restructurer le stream du programme ou utiliser un petit” GOTO “à la place.” Un GOTO est une solution de rechange faible lorsque vous avez un design faible. Les vélociraptors se nourrissent des faibles .

Parfois, il est valable d’utiliser GOTO comme alternative à la gestion des exceptions dans une seule fonction:

 if (f() == false) goto err_cleanup; if (g() == false) goto err_cleanup; if (h() == false) goto err_cleanup; return; err_cleanup: ... 

Le code COM semble tomber assez souvent dans ce modèle.

Je ne peux que rappeler en utilisant un goto une fois. J’ai eu une série de cinq boucles comptées nestedes et je devais pouvoir sortir de toute la structure de l’intérieur plus tôt en fonction de certaines conditions:

 for{ for{ for{ for{ for{ if(stuff){ GOTO ENDOFLOOPS; } } } } } } ENDOFLOOPS: 

J’aurais pu facilement déclarer une variable de rupture booléenne et l’utiliser comme condition pour chaque boucle, mais dans ce cas, j’ai décidé qu’un GOTO était aussi pratique et aussi lisible.

Aucun vélocirapteur ne m’a attaqué.

Nous avons déjà eu cette discussion et je maintiens mon sharepoint vue .

En outre, j’en ai marre des gens qui décrivent des structures de langage de niveau supérieur comme étant «déguisées», car elles n’ont manifestement pas le sens du tout . Par exemple:

Même la structure de contrôle de continuation avancée de Scheme peut être décrite comme un goto sophistiqué.

C’est un non-sens complet. Chaque structure de contrôle peut être implémentée en termes de goto mais cette observation est absolument sortingviale et inutile. goto n’est pas considéré comme nuisible à cause de ses effets positifs, mais à cause de ses conséquences négatives et celles-ci ont été éliminées par une programmation structurée.

De même, dire “GOTO est un outil, et comme tous les outils, il peut être utilisé et abusé” est complètement hors de propos. Aucun ouvrier du bâtiment moderne n’utiliserait un rocher et affirmerait que «c’est un outil». Les pierres ont été remplacées par des marteaux. goto a été remplacé par des structures de contrôle. Si le travailleur de la construction était bloqué dans la nature sans marteau, il utiliserait bien sûr un rocher à la place. Si un programmeur doit utiliser un langage de programmation inférieur qui ne comporte pas la fonctionnalité X, bien sûr, elle devra utiliser goto place. Mais si elle l’utilise ailleurs au lieu de la fonctionnalité de langue appropriée, elle n’a clairement pas bien compris la langue et l’utilise à tort. C’est vraiment aussi simple que ça.

Goto est extrêmement bas sur ma liste de choses à inclure dans un programme juste pour le plaisir. Cela ne veut pas dire que c’est inacceptable.

Goto peut être intéressant pour les machines d’état. Une instruction de commutation dans une boucle est (par ordre d’importance): (a) pas réellement représentative du stream de contrôle, (b) moche, (c) potentiellement inefficace selon la langue et le compilateur. Donc, vous finissez par écrire une fonction par état et vous faites des choses comme “retourner NEXT_STATE”; qui ressemble même à goto.

Certes, il est difficile de coder les machines à états d’une manière qui les rend faciles à comprendre. Cependant, aucune de ces difficultés n’est liée à l’utilisation de goto, et rien ne peut être réduit en utilisant des structures de contrôle alternatives. A moins que votre langage ne possède une construction “machine d’état”. Le mien ne le fait pas.

Dans les rares cas où votre algorithme est vraiment plus compréhensible en termes de chemin à travers une séquence de nœuds (états) connectés par un ensemble limité de transitions admissibles (gotos), plutôt que par un stream de contrôle plus spécifique (boucles, conditionnels, etc.) ), alors cela devrait être explicite dans le code. Et vous devriez dessiner un joli diagramme.

setjmp / longjmp peut être utile pour implémenter des exceptions ou un comportement d’exception. Bien qu’elles ne soient pas universellement louées, les exceptions sont généralement considérées comme une structure de contrôle “valide”.

setjmp / longjmp sont «plus dangereux» que goto dans le sens où ils sont plus difficiles à utiliser correctement, peu importe de manière compréhensible.

Il n’y a jamais eu et il n’y aura jamais de langage dans lequel il est difficile d’écrire du code erroné. – Donald Knuth.

Prendre goto en dehors de C ne faciliterait pas l’écriture d’un bon code en C. En fait, il serait préférable de ne pas comprendre le fait que C est censé être un langage d’assembleur glorifié.

Ensuite, il s’agira de “pointeurs considérés comme nuisibles”, puis “dactylographie considérée comme nuisible”. Alors, qui sera laissé pour vous défendre quand ils viendront vous enlever votre concept de programmation dangereux? Hein?

Sous Linux: Utiliser goto Dans Kernel Code sur Kernel Trap, il y a une discussion avec Linus Torvalds et un “nouveau” sur l’utilisation des GOTO dans le code Linux. Il y a de très bons points là-bas et Linus habillé de cette arrogance habituelle 🙂

Quelques passages:

Linus: “Non, vous avez été soumis à un lavage de cerveau par des personnes du CS qui pensaient que Niklaus Wirth savait en fait de quoi il parlait. Il ne l’a pas fait.

Linus: “Je pense que les choses vont bien, et elles sont souvent plus lisibles que de grandes quantités d’indentation.”

Linus: “Bien sûr, dans les langages stupides comme Pascal, où les étiquettes ne peuvent pas être descriptives, les goto peuvent être mauvais.”

En C, goto ne fonctionne que dans le cadre de la fonction actuelle, ce qui tend à localiser les éventuels bogues. setjmp et longjmp sont beaucoup plus dangereux, étant non-local, compliqué et dépendant de l’implémentation. En pratique cependant, ils sont trop obscurs et peu communs pour causer de nombreux problèmes.

Je crois que le danger de goto in C est grandement exagéré. Rappelez-vous que les arguments goto originaux remontaient à l’époque des langages tels que le BASIC à l’ancienne, où les débutants pouvaient écrire un code spaghetti comme ceci:

 3420 IF A > 2 THEN GOTO 1430 

Ici, Linus décrit une utilisation appropriée de goto : http://www.kernel.org/doc/Documentation/CodingStyle (chapitre 7).

Aujourd’hui, il est difficile de comprendre le problème de la déclaration GOTO parce que les gens de la “programmation structurée” ont surtout gagné le débat et que les langages actuels ont suffisamment de structures de contrôle pour éviter la GOTO .

Comptez le nombre de goto dans un programme C moderne. Ajoutez maintenant le nombre d’ break , de continue et de return . En outre, ajoutez le nombre de fois que vous utilisez if , else , while , switch ou case . C’est à peu près combien de GOTO votre programme aurait eu si vous écriviez dans FORTRAN ou BASIC en 1968 quand Dijkstra a écrit sa lettre.

Les langages de programmation à l’époque manquaient de stream de contrôle. Par exemple, dans le BASIC Dartmouth original:

  • IF déclarations IF n’avaient aucune ELSE . Si vous en voulez un, vous devez écrire:

     100 IF NOT condition THEN GOTO 200 ...stuff to do if condition is true... 190 GOTO 300 200 REM else ...stuff to do if condition is false... 300 REM end if 
  • Même si votre déclaration IF n’avait pas besoin d’une ELSE , elle était toujours limitée à une seule ligne, qui consistait généralement en un GOTO .

  • Il n’y avait pas de déclaration DO...LOOP . Pour les boucles non FOR , vous devez terminer la boucle avec un GOTO ou un IF...GOTO explicite au début.

  • Il n’y avait pas de SELECT CASE . Il fallait utiliser ON...GOTO .

Donc, vous avez fini avec beaucoup de GOTO dans votre programme. Et vous ne pouviez pas dépendre de la ressortingction des GOTO dans un seul sous-programme (parce que GOSUB...RETURN était un concept si faible de sous-routines), donc ces GOTO pourraient aller n’importe où . De toute évidence, cela rendait le stream de contrôle difficile à suivre.

C’est de là que vient le mouvement anti- GOTO .

Go To peut fournir une sorte de solution de rechange pour la gestion “réelle” des exceptions dans certains cas. Considérer:

 ptr = malloc(size); if (!ptr) goto label_fail; bytes_in = read(f_in,ptr,size); if (bytes_in=<0) goto label_fail; bytes_out = write(f_out,ptr,bytes_in); if (bytes_out != bytes_in) goto label_fail; 

Évidemment, ce code a été simplifié pour prendre moins de place, alors ne tenez pas compte des détails. Mais considérez une alternative que j'ai vue trop souvent dans le code de production par les codeurs qui ont pris des mesures absurdes pour éviter d'utiliser goto:

 success=false; do { ptr = malloc(size); if (!ptr) break; bytes_in = read(f_in,ptr,size); if (count=<0) break; bytes_out = write(f_out,ptr,bytes_in); if (bytes_out != bytes_in) break; success = true; } while (false); 

Maintenant, fonctionnellement, ce code fait exactement la même chose. En fait, le code généré par le compilateur est presque identique. Cependant, dans le zèle du programmeur pour apaiser Nogoto (le dieu redoutable de la critique académique), ce programmeur a complètement brisé l'idiome sous-jacent que représente la boucle while et fait un vrai nombre sur la lisibilité du code. Ce n'est pas mieux.

Donc, la morale de l’histoire est que si vous vous trouvez à recourir à quelque chose de vraiment stupide pour éviter d’utiliser goto, alors ne le faites pas.

Donald E. Knuth a répondu à cette question dans le livre “Literate Programming”, 1992 CSLI. Dans. 17 il y a un essai ” Programmation structurée avec goto déclarations ” (PDF). Je pense que l’article pourrait également avoir été publié dans d’autres livres.

L’article décrit la suggestion de Dijkstra et décrit les circonstances dans lesquelles cela est valable. Mais il donne également un certain nombre de contre-exemples (problèmes et algorithmes) qui ne peuvent pas être facilement reproduits en utilisant uniquement des boucles structurées.

L’article contient une description complète du problème, de l’historique, des exemples et des contre-exemples.

Attiré par Jay Ballou ajoutant une réponse, j’appendai mes 0,02 £. Si Bruno Ranschaert ne l’avait pas déjà fait, j’aurais mentionné l’article “Programmation structurée avec déclarations GOTO” de Knuth.

Une chose que je n’ai pas vue discutée est le type de code qui, bien que pas tout à fait commun, a été enseigné dans les manuels Fortran. Des choses comme la plage étendue d’une boucle DO et de sous-routines à code ouvert (rappelez-vous que ce serait Fortran II ou Fortran IV ou Fortran 66 – pas Fortran 77 ou 90). Il y a au moins une chance que les détails syntaxiques soient inexacts, mais les concepts doivent être suffisamment précis. Les extraits dans chaque cas sont dans une seule fonction.

Notez que l’excellent mais daté (et hors du livre) ” Les éléments du style de programmation, 2nd Edn ” de Kernighan & Plauger comprend quelques exemples réels d’abus de GOTO de la programmation de manuels de son époque (fin des années 70). Le matériel ci-dessous ne provient pas de ce livre, cependant.

Portée étendue pour une boucle DO

  do 10 i = 1,30 ...blah... ...blah... if (k.gt.4) goto 37 91 ...blah... ...blah... 10 continue ...blah... return 37 ...some computation... goto 91 

L’une des raisons de ce non-sens était la bonne carte perforée à l’ancienne. Vous remarquerez peut-être que les étiquettes (joliment hors séquence parce que c’était le style canonique!) Se trouvent dans la colonne 1 (en fait, elles devaient figurer dans les colonnes 1 à 5) et le code dans les colonnes 7 à 72 (colonne 6 colonne marqueur). Un numéro de séquence est atsortingbué aux colonnes 73 à 80 et il existe des machines qui classent les jeux de cartes perforées dans l’ordre des numéros de séquence. Si vous aviez votre programme sur des cartes séquencées et que vous deviez append quelques cartes (lignes) au milieu d’une boucle, vous devriez tout repiquer après ces lignes supplémentaires. Cependant, si vous remplacez une carte par des trucs GOTO, vous pouvez éviter de reséquencer toutes les cartes – vous venez de ranger les nouvelles cartes à la fin de la routine avec de nouveaux numéros de séquence. Considérez cela comme la première tentative de «calcul vert» – une économie de cartes perforées (ou, plus précisément, une économie de ré-écriture de la main-d’œuvre – et une économie d’erreurs de relecture consécutives).

Oh, vous pouvez aussi noter que je sortingche et que je ne crie pas – Fortran IV a été écrit dans toutes les majuscules normalement.

Sous-programme à code ouvert

  ...blah... i = 1 goto 76 123 ...blah... ...blah... i = 2 goto 76 79 ...blah... ...blah... goto 54 ...blah... 12 continue return 76 ...calculate something... ...blah... goto (123, 79) i 54 ...more calculation... goto 12 

Le GOTO entre les étiquettes 76 et 54 est une version de goto calculé. Si la variable i a la valeur 1, passez à la première étiquette de la liste (123); si elle a la valeur 2, passez à la seconde, et ainsi de suite. Le fragment de 76 au goto calculé est le sous-programme à code ouvert. C’était un morceau de code exécuté plutôt comme un sous-programme, mais écrit dans le corps d’une fonction. (Fortran avait également des fonctions de déclaration – qui étaient des fonctions intégrées sur une seule ligne.)

Il y avait des constructions plus mauvaises que le goto calculé – vous pouviez assigner des étiquettes aux variables et utiliser un goto assigné. Googling assigné goto me dit qu’il a été supprimé de Fortran 95. Craignez-en une pour la révolution de programmation structurée qui pourrait être considérée comme ayant commencé en public avec la lettre ou l’article “GOTO Considéré Nocif” de Dijkstra.

Without some knowledge of the sorts of things that were done in Fortran (and in other languages, most of which have rightly fallen by the wayside), it is hard for us newcomers to understand the scope of the problem which Dijkstra was dealing with. Heck, I didn’t start programming until ten years after that letter was published (but I did have the misfortune to program in Fortran IV for a while).

Goto considered helpful.

I started programming in 1975. To 1970s-era programmers, the words “goto considered harmful” said more or less that new programming languages with modern control structures were worth trying. We did try the new languages. We quickly converted. We never went back.

We never went back, but, if you are younger, then you have never been there in the first place.

Now, a background in ancient programming languages may not be very useful except as an indicator of the programmer’s age. Notwithstanding, younger programmers lack this background, so they no longer understand the message the slogan “goto considered harmful” conveyed to its intended audience at the time it was introduced.

Slogans one does not understand are not very illuminating. It is probably best to forget such slogans. Such slogans do not help.

This particular slogan however, “Goto considered harmful,” has taken on an undead life of its own.

Can goto not be abused? Answer: sure, but so what? Practically every programming element can be abused. The humble bool for example is abused more often than some of us would like to believe.

By contrast, I cannot remember meeting a single, actual instance of goto abuse since 1990.

The biggest problem with goto is probably not technical but social. Programmers who do not know very much sometimes seem to feel that deprecating goto makes them sound smart. You might have to satisfy such programmers from time to time. Such is life.

The worst thing about goto today is that it is not used enough.

There is no such things as GOTO considered harmful .

GOTO is a tool, and as all tools, it can be used and abused .

There are, however, many tools in the programming world that have a tendency to be abused more than being used , and GOTO is one of them. the WITH statement of Delphi is another.

Personally I don’t use either in typical code , but I’ve had the odd usage of both GOTO and WITH that were warranted, and an alternative solution would’ve contained more code.

The best solution would be for the comstackr to just warn you that the keyword was tainted , and you’d have to stuff a couple of pragma directives around the statement to get rid of the warnings.

It’s like telling your kids to not run with scissors . Scissors are not bad, but some usage of them are perhaps not the best way to keep your health.

Since I began doing a few things in the linux kernel, gotos don’t bother me so much as they once did. At first I was sort of horrified to see they (kernel guys) added gotos into my code. I’ve since become accustomed to the use of gotos, in some limited contexts, and will now occasionally use them myself. Typically, it’s a goto that jumps to the end of a function to do some kind of cleanup and bail out, rather than duplicating that same cleanup and bailout in several places in the function. And typically, it’s not something large enough to hand off to another function — eg freeing some locally (k)malloc’ed variables is a typical case.

I’ve written code that used setjmp/longjmp only once. It was in a MIDI drum sequencer program. Playback happened in a separate process from all user interaction, and the playback process used shared memory with the UI process to get the limited info it needed to do the playback. When the user wanted to stop playback, the playback process just did a longjmp “back to the beginning” to start over, rather than some complicated unwinding of wherever it happened to be executing when the user wanted it to stop. It worked great, was simple, and I never had any problems or bugs related to it in that instance.

setjmp/longjmp have their place — but that place is one you’ll not likely visit but once in a very long while.

Edit: I just looked at the code. It was actually siglongjmp() that I used, not longjmp (not that it’s a big deal, but I had forgotten that siglongjmp even existed.)

It never was, as long as you were able to think for yourself.

If you’re writing a VM in C, it turns out that using (gcc’s) computed gotos like this:

 char run(char *pc) { void *opcodes[3] = {&&op_inc, &&op_lda_direct, &&op_hlt}; #define NEXT_INSTR(ssortingde) goto *(opcodes[*(pc += ssortingde)]) NEXT_INSTR(0); op_inc: ++acc; NEXT_INSTR(1); op_lda_direct: acc = ram[++pc]; NEXT_INSTR(1); op_hlt: return acc; } 

works much faster than the conventional switch inside a loop.

Because goto can be used for confusing metaprogramming

Goto is both a high-level and a low-level control expression, and as a result it just doesn’t have a appropriate design pattern suitable for most problems.

It’s low-level in the sense that a goto is a primitive operation that implements something higher like while or foreach or something.

It’s high-level in the sense that when used in certain ways it takes code that executes in a clear sequence, in an uninterrupted fashion, except for structured loops, and it changes it into pieces of logic that are, with enough goto s, a grab-bag of logic being dynamically reassembled.

So, there is a prosaic and an evil side to goto .

The prosaic side is that an upward pointing goto can implement a perfectly reasonable loop and a downward-pointing goto can do a perfectly reasonable break or return . Of course, an actual while , break , or return would be a lot more readable, as the poor human wouldn’t have to simulate the effect of the goto in order to get the big picture. So, a bad idea in general.

The evil side involves a routine not using goto for while, break, or return, but using it for what’s called spaghetti logic . In this case the goto-happy developer is constructing pieces of code out of a maze of goto’s, and the only way to understand it is to simulate it mentally as a whole, a terribly tiring task when there are many goto’s. I mean, imagine the trouble of evaluating code where the else is not precisely an inverse of the if , where nested if s might allow in some things that were rejected by the outer if , etc, etc.

Finally, to really cover the subject, we should note that essentially all early languages except Algol initially made only single statements subject to their versions of if-then-else . So, the only way to do a conditional block was to goto around it using an inverse conditional. Insane, I know, but I’ve read some old specs. Remember that the first computers were programmed in binary machine code so I suppose any kind of an HLL was a lifesaver; I guess they weren’t too picky about exactly what HLL features they got.

Having said all that I used to stick one goto into every program I wrote “just to annoy the purists” .

Denying the use of the GOTO statement to programmers is like telling a carpenter not to use a hammer as it Might damage the wall while he is hammering in a nail. A real programmer Knows How and When to use a GOTO. I’ve followed behind some of these so-called ‘Structured Programs’ I’ve see such Horrid code just to avoid using a GOTO, that I could shoot the programmer. Ok, In defense of the other side, I’ve seen some real spaghetti code too and again, those programmers should be shot too.

Here is just one small example of code I’ve found.

  YORN = '' LOOP UNTIL YORN = 'Y' OR YORN = 'N' DO CRT 'Is this correct? (Y/N) : ': INPUT YORN REPEAT IF YORN = 'N' THEN CRT 'Aborted!' STOP END 

———————–OR———————-

 10: CRT 'Is this Correct (Y)es/(N)o ': INPUT YORN IF YORN='N' THEN CRT 'Aborted!' STOP ENDIF IF YORN<>'Y' THEN GOTO 10 

The original paper should be thought of as “Unconditional GOTO Considered Harmful”. It was in particular advocating a form of programming based on conditional ( if ) and iterative ( while ) constructs, rather than the test-and-jump common to early code. goto is still useful in some languages or circumstances, where no appropriate control structure exists.

“In this link http://kerneltrap.org/node/553/2131

Ironically, eliminating the goto introduced a bug: the spinlock call was omitted.

About the only place I agree Goto could be used is when you need to deal with errors, and each particular point an error occurs requires special handling.

For instance, if you’re grabbing resources and using semaphores or mutexes, you have to grab them in order and you should always release them in the opposite manner.

Some code requires a very odd pattern of grabbing these resources, and you can’t just write an easily maintained and understood control structure to correctly handle both the grabbing and releasing of these resources to avoid deadlock.

It’s always possible to do it right without goto, but in this case and a few others Goto is actually the better solution primarily for readability and maintainability.

-Adam

One modern GOTO usage is by the C# comstackr to create state machines for enumerators defined by yield return.

GOTO is something that should be used by comstackrs and not programmers.

Until C and C++ (amongst other culprits) have labelled breaks and continues, goto will continue to have a role.

I avoid it since a coworker/manager will undoubtedly question its use either in a code review or when they stumble across it. While I think it has uses (the error handling case for example) – you’ll run afoul of some other developer who will have some type of problem with it.

It’s not worth it.

If GOTO itself were evil, comstackrs would be evil, because they generate JMPs. If jumping into a block of code, especially following a pointer, were inherently evil, the RETurn instruction would be evil. Rather, the evil is in the potential for abuse.

At times I have had to write apps that had to keep track of a number of objects where each object had to follow an insortingcate sequence of states in response to events, but the whole thing was definitely single-thread. A typical sequence of states, if represented in pseudo-code would be:

 request something wait for it to be done while some condition request something wait for it if one response while another condition request something wait for it do something endwhile request one more thing wait for it else if some other response ... some other similar sequence ... ... etc, etc. endwhile 

I’m sure this is not new, but the way I handled it in C(++) was to define some macros:

 #define WAIT(n) do{state=(n); enque(this); return; L##n:;}while(0) #define DONE state = -1 #define DISPATCH0 if state < 0) return; #define DISPATCH1 if(state==1) goto L1; DISPATCH0 #define DISPATCH2 if(state==2) goto L2; DISPATCH1 #define DISPATCH3 if(state==3) goto L3; DISPATCH2 #define DISPATCH4 if(state==4) goto L4; DISPATCH3 ... as needed ... 

Then (assuming state is initially 0) the structured state machine above turns into the structured code:

 { DISPATCH4; // or as high a number as needed request something; WAIT(1); // each WAIT has a different number while (some condition){ request something; WAIT(2); if (one response){ while (another condition){ request something; WAIT(3); do something; } request one more thing; WAIT(4); } else if (some other response){ ... some other similar sequence ... } ... etc, etc. } DONE; } 

With a variation on this, there can be CALL and RETURN, so some state machines can act like subroutines of other state machines.

Is it unusual? Oui. Does it take some learning on the part of the maintainer? Oui. Does that learning pay off? Je le pense. Could it be done without GOTOs that jump into blocks? Nan.

I actually found myself forced to use a goto, because I literally couldn’t think of a better (faster) way to write this code:

I had a complex object, and I needed to do some operation on it. If the object was in one state, then I could do a quick version of the operation, otherwise I had to do a slow version of the operation. The thing was that in some cases, in the middle of the slow operation, it was possible to realise that this could have been done with the fast operation.

 SomeObject someObject; if (someObject.IsComplex()) // this test is sortingvial { // begin slow calculations here if (result of calculations) { // just discovered that I could use the fast calculation ! goto Fast_Calculations; } // do the rest of the slow calculations here return; } if (someObject.IsmediumComplex()) // this test is slightly less sortingvial { Fast_Calculations: // Do fast calculations return; } // object is simple, no calculations needed. 

This was in a speed critical piece of realtime UI code, so I honestly think that a GOTO was justified here.

Hugo

Almost all situations where a goto can be used, you can do the same using other constructs. Goto is used by the comstackr anyway.

I personally never use it explicitly, don’t ever need to.

One thing I’ve not seen from any of the answers here is that a ‘goto’ solution is often more efficient than one of the structured programming solutions often mentioned.

Consider the many-nested-loops case, where using ‘goto’ instead of a bunch of if(breakVariable) sections is obviously more efficient. The solution “Put your loops in a function and use return” is often totally unreasonable. In the likely case that the loops are using local variables, you now have to pass them all through function parameters, potentially handling loads of extra headaches that arise from that.

Now consider the cleanup case, which I’ve used myself quite often, and is so common as to have presumably been responsible for the try{} catch {} structure not available in many languages. The number of checks and extra variables that are required to accomplish the same thing are far worse than the one or two instructions to make the jump, and again, the additional function solution is not a solution at all. You can’t tell me that’s more manageable or more readable.

Now code space, stack usage, and execution time may not matter enough in many situations to many programmers, but when you’re in an embedded environment with only 2KB of code space to work with, 50 bytes of extra instructions to avoid one clearly defined ‘goto’ is just laughable, and this is not as rare a situation as many high-level programmers believe.

The statement that ‘goto is harmful’ was very helpful in moving towards structured programming, even if it was always an over-generalization. At this point, we’ve all heard it enough to be wary of using it (as we should). When it’s obviously the right tool for the job, we don’t need to be scared of it.

You can use it for breaking from a deeply nested loop, but most of the time your code can be refactored to be cleaner without deeply nested loops.