GOTO still considered harmful? [closed]
Asked Answered
T

49

316

Everyone is aware of Dijkstra's Letters to the editor: go to statement considered harmful (also here .html transcript and here .pdf) and there has been a formidable push since that time to eschew the goto statement whenever possible. While it's possible to use goto to produce unmaintainable, sprawling code, it nevertheless remains in modern programming languages. Even the advanced continuation control structure in Scheme can be described as a sophisticated goto.

What circumstances warrant the use of goto? When is it best to avoid?

As a follow-up question: C provides a pair of functions, setjmp() and longjmp(), that provide the ability to goto not just within the current stack frame but within any of the calling frames. Should these be considered as dangerous as goto? More dangerous?


Dijkstra himself regretted that title, for which he was not responsible. At the end of EWD1308 (also here .pdf) he wrote:

Finally a short story for the record. In 1968, the Communications of the ACM published a text of mine under the title "The goto statement considered harmful", which in later years would be most frequently referenced, regrettably, however, often by authors who had seen no more of it than its title, which became a cornerstone of my fame by becoming a template: we would see all sorts of articles under the title "X considered harmful" for almost any X, including one titled "Dijkstra considered harmful". But what had happened? I had submitted a paper under the title "A case against the goto statement", which, in order to speed up its publication, the editor had changed into a "letter to the Editor", and in the process he had given it a new title of his own invention! The editor was Niklaus Wirth.

A well thought out classic paper about this topic, to be matched to that of Dijkstra, is Structured Programming with go to Statements, by Donald E. Knuth. Reading both helps to reestablish context and a non-dogmatic understanding of the subject. In this paper, Dijkstra's opinion on this case is reported and is even more strong:

Donald E. Knuth: I believe that by presenting such a view I am not in fact disagreeing sharply with Dijkstra's ideas, since he recently wrote the following: "Please don't fall into the trap of believing that I am terribly dogmatical about [the go to statement]. I have the uncomfortable feeling that others are making a religion out of it, as if the conceptual problems of programming could be solved by a single trick, by a simple form of coding discipline!"

Thaumaturgy answered 5/9, 2008 at 19:5 Comment(20)
C#'s goto is not the same as the goto Dijkstra was talking about, for precisely the reasons that Dijkstra talked about. That goto is both a harmful as it was back then, but also a lot less necessary, because modern languages provide alternative control structures. C# goto is extremely constrained.Skep
I love it, Dijkstra himself is irritated by the flood of 'blah blah considered harmful' articles. I'm getting pretty tired of the phrase.Spermatophyte
First it was a cliché, but at some point it was transformed into an obvious joke.Thaumaturgy
.. such as: "Not reading original sources considered harmful" or "Crowd-thinking considered even more harmful".Thaumaturgy
Gotos are good when they add clearity. If you have a long nested loop, it can be better to goto out of it than setting "break" variables and breaking until you get out.Rettarettig
@simendsjo: However, I have yet to see a place when it actually adds clarity. With a break, you know where you'll go - there's no such guarantee in a goto. <han_solo>Without precise calculations you could fly right through a star, or bounce too close to a supernova and that'd end your trip real quick, wouldn't it?</han_solo>Capet
If you have a nested loop on 4 depths (not that it's a good thing), breaking out of all requires setting temporary values. A goto here is much clearer to me, and the IDE should easily show where the goto is. That said, the use of goto should be sparse, and in my opinion only move down to skip codeRettarettig
Read about Spaghetti Code to understand the problem: en.wikipedia.org/wiki/Spaghetti_codeSterlingsterlitamak
I suggest you go read the nine thousand and one threads tagged goto.Facetious
This is the original reference for the criticism of goto: userweb.cs.utexas.edu/users/EWD/ewd02xx/EWD215.PDF Goto promotes spaghetti code, so is very hard to understand and debug.Creation
Take time and read: Go To Statement Considered HarmfulEmbryology
I think it's Velociraptor-safe when used in Excel.Verdi
I would imagine a goto here and there can make writing a compiler easier for some obtuse language structures that you want to implement. By that, I mean the generated code has goto, not necessarily the compiler itself.Robenarobenia
"setjmp and longjmp are specified to not be a part of the C language. They are included in an informative annex to the specification " -- utter nonsense.Selfridge
After years of experience, I'd bluntly summarize good and bad coding practices as follows: the best program you can write is the shortest program that can be properly maintained by any (sufficiently skilled) developer. I say blunt, because there are a lot of tricky sidenotes, such as 'complexity'. Still, if you look at 'goto's, most uses of that statement will add code which can be removed with loops, if, etc. There are rare exceptions though, (f.ex. en.wikipedia.org/wiki/Open_addressing - note 1) where I think I would prefer a 'goto' to all longer and complexer alternatives.Internationalist
@Pekka You are incorrect. setjmp and longjmp have always been core functions mandated for every implementation of the C language. For instance, they are specified in ISO 9899:2011§7.13.Organist
There is one thing clearly worse than using goto: hacking structured programming tools together to implement a goto.Biweekly
Sorry but the question caught my eye "Still considered harmful?". Goto statements will ALWAYS be considered harmful if you care about good software design and practices.Jumbled
If you still make software in low-level languages then there is sometimes no way around using the machine-code equivalent of GOTO - yes I know that not many people use MC/Assembly nowadays but the ZX Spectrum Next will see a mini-revival in Z80 for a short while at least. JP $0010Stoddard
Knuth’s article link is dead. Here is a new link: pic.plover.com/knuth-GOTO.pdfPlastered
S
202

The following statements are generalizations; while it is always possible to plead exception, it usually (in my experience and humble opinion) isn't worth the risks.

  1. Unconstrained use of memory addresses (either GOTO or raw pointers) provides too many opportunities to make easily avoidable mistakes.
  2. The more ways there are to arrive at a particular "location" in the code, the less confident one can be about what the state of the system is at that point. (See below.)
  3. Structured programming IMHO is less about "avoiding GOTOs" and more about making the structure of the code match the structure of the data. For example, a repeating data structure (e.g. array, sequential file, etc.) is naturally processed by a repeated unit of code. Having built-in structures (e.g. while, for, until, for-each, etc.) allows the programmer to avoid the tedium of repeating the same cliched code patterns.
  4. Even if GOTO is low-level implementation detail (not always the case!) it's below the level that the programmer should be thinking. How many programmers balance their personal checkbooks in raw binary? How many programmers worry about which sector on the disk contains a particular record, instead of just providing a key to a database engine (and how many ways could things go wrong if we really wrote all of our programs in terms of physical disk sectors)?

Footnotes to the above:

Regarding point 2, consider the following code:

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

At the "do something" point in the code, we can state with high confidence that a is greater than b. (Yes, I'm ignoring the possibility of untrapped integer overflow. Let's not bog down a simple example.)

On the other hand, if the code had read this way:

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

The multiplicity of ways to get to label 10 means that we have to work much harder to be confident about the relationships between a and b at that point. (In fact, in the general case it's undecideable!)

Regarding point 4, the whole notion of "going someplace" in the code is just a metaphor. Nothing is really "going" anywhere inside the CPU except electrons and photons (for the waste heat). Sometimes we give up a metaphor for another, more useful, one. I recall encountering (a few decades ago!) a language where

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

was implemented on a virtual machine by compiling action-1 and action-2 as out-of-line parameterless routines, then using a single two-argument VM opcode which used the boolean value of the condition to invoke one or the other. The concept was simply "choose what to invoke now" rather than "go here or go there". Again, just a change of metaphor.

Spillage answered 5/9, 2008 at 19:5 Comment(6)
A good point. In higher-level languages goto doesn't really even mean anything (consider jumping between methods in Java). A Haskell function may consist of a single expression; try jumping out of that with a goto!Recha
Postscript works like your point 4 example.Schuh
Smalltalk works similarly to the point 4 example, if by "similarly" you mean "nothing like procedural languages do". :P There's no flow control in the language; all decisions are handled via polymorphism (true and false are of different types), and each branch of an if/else is basically a lambda.Tapdance
These are valid points, but in the end they just reiterate how bad goto can be "if misused". Break, continue, exit, return, gosub, settimeout, global, include, etc. are all modern techniques that require mentally tracing the flow of things and can all be misused to create spaghetti code and skip around to create uncertainty of variable states. To be fair, though I've never seen a bad use of goto first-hand, I've also only ever seen it used once or twice. That speaks to the statement that there are most always better things to use.Poised
goto in a modern programming language (Go) https://mcmap.net/q/24120/-why-does-go-have-a-quot-goto-quot-statement-closed.Lyman
@Nishanths The example presented in that case is very unlike most industrial/commercial application code that I have seen. And one of the comments provides an alternative that (modulo the raw speed requirements of a performance-intensive math library) easily expresses the same intent without a goto.Spillage
L
268

XKCD's GOTO Comic

A coworker of mine said the only reason to use a GOTO is if you programmed yourself so far into a corner that it is the only way out. In other words, proper design ahead of time and you won't need to use a GOTO later.

I thought this comic illustrates that beautifully "I could restructure the program's flow, or use one little 'GOTO' instead." A GOTO is a weak way out when you have weak design. Velociraptors prey on the weak.

Landin answered 5/9, 2008 at 19:5 Comment(15)
GOTO can make 'jump'ing from one arbitrary spot to another arbitrary spot. Velociraptor jumped to here from nowhere!Souse
i dont find the joke funny at all because everybody knows that you also have to link before you can execute.Sewel
Your coworker is wrong, and obviously didn't read Knuth's paper.Selfridge
I think I will restructure everything instead...Gifferd
@KinjalDixit This is obviously what happens in the third box (or maybe anti-box, since it does not have a frame). Didn't noticed? :DBulrush
I think the only reason to use goto is when you are debugging (testing certain parts of your code) and you just need to jump to certain place (e.g. if block) and test it. So you apply goto, test, and then delete goto.Unstrung
@Unstrung These are the cases where it's prudent to create a driver file for test cases (a second main, if you will). That way, you can simply call the routine directly.Lorelle
@SeanAllred debugging != Unit test. It's more when you have a bunch of procedural code and you need to figure out how it works. ImhoUnstrung
I have seen no end of obfuscated and otherwise contorted code over the years put in place just to avoid a goto. @jimmcKeeth, The xkcd cartoon above doesn't establish that goto is weak. It's making fun of the hysteria around using it.Wavelet
@tgm1024: Inexperienced programmers will write obfuscated and contorted code with or without goto. That's a measure of the programmer, not of goto. Experienced programmers usually write clear code without goto... And you might want to check out the mouse-over text of the comic... which refers to the author of, and one of the protagonists in, the novel "Cryptonomicon"... so I think you might have misinterpreted the message of the cartoon a bit. ;-)Paleontology
You do realise that the Delphi library source code contains goto statements. And these are appropriate uses of goto.Splatter
@DavidHeffernan If you can avoid GOTO you still should.Landin
@JimMcKeeth Not so. Some algorithms are easier to understand with goto. There are very few examples, but there are some. In the RTL we have examples in System, System.Generics.Defaults and Vcl.Imaging.GIFImg. You could ask your colleagues why they are there. You can find examples in GR32 and Synopse libraries. This is code written by skilled developers. There are none my code base. But I don't think one needs to be quite so dogmatic about it.Splatter
explainxkcd.com/wiki/index.php/292:_gotoLilialiliaceous
Goto is really bad in OOP code that uses inheritance. However, the procedural goto code when used correctly isn't as bad as inheritance, or tons of classes all talking to each other by reference... Seriously, don't use getters and setters instead create a new object everytime you want an object with a different state your code will be much much less brittle.Kleon
S
202

The following statements are generalizations; while it is always possible to plead exception, it usually (in my experience and humble opinion) isn't worth the risks.

  1. Unconstrained use of memory addresses (either GOTO or raw pointers) provides too many opportunities to make easily avoidable mistakes.
  2. The more ways there are to arrive at a particular "location" in the code, the less confident one can be about what the state of the system is at that point. (See below.)
  3. Structured programming IMHO is less about "avoiding GOTOs" and more about making the structure of the code match the structure of the data. For example, a repeating data structure (e.g. array, sequential file, etc.) is naturally processed by a repeated unit of code. Having built-in structures (e.g. while, for, until, for-each, etc.) allows the programmer to avoid the tedium of repeating the same cliched code patterns.
  4. Even if GOTO is low-level implementation detail (not always the case!) it's below the level that the programmer should be thinking. How many programmers balance their personal checkbooks in raw binary? How many programmers worry about which sector on the disk contains a particular record, instead of just providing a key to a database engine (and how many ways could things go wrong if we really wrote all of our programs in terms of physical disk sectors)?

Footnotes to the above:

Regarding point 2, consider the following code:

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

At the "do something" point in the code, we can state with high confidence that a is greater than b. (Yes, I'm ignoring the possibility of untrapped integer overflow. Let's not bog down a simple example.)

On the other hand, if the code had read this way:

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

The multiplicity of ways to get to label 10 means that we have to work much harder to be confident about the relationships between a and b at that point. (In fact, in the general case it's undecideable!)

Regarding point 4, the whole notion of "going someplace" in the code is just a metaphor. Nothing is really "going" anywhere inside the CPU except electrons and photons (for the waste heat). Sometimes we give up a metaphor for another, more useful, one. I recall encountering (a few decades ago!) a language where

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

was implemented on a virtual machine by compiling action-1 and action-2 as out-of-line parameterless routines, then using a single two-argument VM opcode which used the boolean value of the condition to invoke one or the other. The concept was simply "choose what to invoke now" rather than "go here or go there". Again, just a change of metaphor.

Spillage answered 5/9, 2008 at 19:5 Comment(6)
A good point. In higher-level languages goto doesn't really even mean anything (consider jumping between methods in Java). A Haskell function may consist of a single expression; try jumping out of that with a goto!Recha
Postscript works like your point 4 example.Schuh
Smalltalk works similarly to the point 4 example, if by "similarly" you mean "nothing like procedural languages do". :P There's no flow control in the language; all decisions are handled via polymorphism (true and false are of different types), and each branch of an if/else is basically a lambda.Tapdance
These are valid points, but in the end they just reiterate how bad goto can be "if misused". Break, continue, exit, return, gosub, settimeout, global, include, etc. are all modern techniques that require mentally tracing the flow of things and can all be misused to create spaghetti code and skip around to create uncertainty of variable states. To be fair, though I've never seen a bad use of goto first-hand, I've also only ever seen it used once or twice. That speaks to the statement that there are most always better things to use.Poised
goto in a modern programming language (Go) https://mcmap.net/q/24120/-why-does-go-have-a-quot-goto-quot-statement-closed.Lyman
@Nishanths The example presented in that case is very unlike most industrial/commercial application code that I have seen. And one of the comments provides an alternative that (modulo the raw speed requirements of a performance-intensive math library) easily expresses the same intent without a goto.Spillage
L
146

Sometimes it is valid to use GOTO as an alternative to exception handling within a single function:

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

COM code seems to fall into this pattern fairly often.

Lilla answered 5/9, 2008 at 19:5 Comment(11)
Just because COM code does it doesn't make it correct. How about move the err_cleanup code into it's own subroutine?Traveled
I've done the error cleanup stuff in C. In C++ I would use a try block instead.Loki
I agree, there are legitimate use cases where, goto can simplify code and make it more readable/maintainable, but there seems to be some sort of goto-phobia floating around ...Reaves
@Bob: It's hard to move the err_cleanup code into a subroutine if it's cleaning up local variables.Seriocomic
Actually, I used it in COM/VB6 just because I had no alternative, not because it was an alternative. How happy I am nowadays with try / catch / finally.Walk
Why not use CComPtrs and smart pointers in general?Scribble
@Loki The idiomatic C++ way is not try {} catch() { cleanup; }, but rather, RAII, where resources that need to be cleaned up are done so in destructors. Every constructor / destructor manages exactly one resource.Kibosh
This usage of goto, along with 'single return' style are standard practice at Apple. I was a little shocked at first but it's functionally equivalent to try/catch and very fast and portable.Maintain
There are two ways of writing this in C without goto; and both are much shorter. Either: if(f())if(g())if(h()) return success; cleanup(); return failure; or: if(f() && g() && h()) return success; cleanup(); return failure;Entwine
As does Linux kernel code: kernel.org/doc/Documentation/CodingStyle and in fact a lot of C code. This idiom is the only use of goto mentioned in Vine's "C Programming for the Absolute Beginner" ISBN 1598636340Lava
Comparing booleans is also evil by the way.Shornick
L
138

I can only recall using a goto once. I had a series of five nested counted loops and I needed to be able to break out of the entire structure from the inside early based on certain conditions:

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

I could just have easily declared a boolean break variable and used it as part of the conditional for each loop, but in this instance I decided a GOTO was just as practical and just as readable.

No velociraptors attacked me.

Lawler answered 5/9, 2008 at 19:5 Comment(26)
depending on the language, in C# for things like this, you can use labeled break instead of goto, which is the same thing I guess.Sisneros
"Refactor it into a function and replace goto with return :)", and the difference is? really what's the difference? isn't return a go to also? Returns also brakes the structured flow of like goto does, and in this case they do it the same way (even if goto can be used for meaner things)Reaves
Pop: How does return break the structured flow?Skep
if you have a method "christmasTreeOfForLoops()" when you want to break in the outer for, you simply return. That is the equivalent of a break at the outer loop level.Prospect
+1: I use the equivalent Java tool and I've missed it in C in the past.Antonioantonius
This is a kind of glorified exception throwing and is a good example for how heavy most exception syntax is.Gonsalve
Nesting lots of loops is usually a code smell all it's own. Unless you are doing, like, 5-dimensional array multiplication, it's hard to picture a situation where some of the inner loops couldn't be usefully extracted into smaller functions. Like all rules of thumb, there are a handful of exceptions I suppose.Adventurer
Replacing it with a return only works if you are using a language that supports returns.Flavin
Five nested loops is too much, it should be refactored. I still give +1 because if you have 2 nested loops then using a goto is simple and efficient.Earwax
Hey, if each of the five loops are only used once and they all fit in a small area (not 1000 lines), then refactoring is a waste of time.Angleaangler
@Jimmy: C# does not have labeled breaks, Java does.Mcreynolds
If you need more than 3 levels of indentation, you're screwed anyway, and should fix your program. - Linus TorvaldsCathee
@leppie: The generation that rebelled against goto and gave us structured programming also rejected early returns, for the same reason. It comes down to how readable the code is, how clearly it expressed the programmer's intent. Creating a function for no other purpose than to avoid using an maligned keyword results in bad cohesion: the cure is worse than the disease.Coridon
@Cathee But most of my code has 3 levels of indentation by default :(. 1 for the namespace, 2 for the class, and 3 for the method.Indolent
In PHP you can break out of as many levels of looping as you want. break 5; in your example.Aldwin
@ButtleButkus: Frankly, that's just as bad, if not worse. At least with a goto, one can explicitly specify the target. With break 5;, (1) i have to count loop closings to find the destination; and (2) if the loop structure ever changes, it may well require changing that number in order to keep the destination correct. If i'm going to avoid goto, then the gain should be in not having to manually track stuff like that.Tapdance
@Tapdance - ...that's why in Ada what they do is let you name your loops. If you want to break out of the loop named outer, you do a break outer; This post isn't a horrible example, but it is one that is only valid due to current limitations of certian specific languages. IMHO the state machine example is far better, as no procedural language I'm aware of supports those in a native control structure.Fregger
@T.E.D.: Java and Perl support named loops as well (or at least use labels in such a way as to act like a named loop...which is good enough for me). As for state machines, i can picture a C'ish language supporting continue within a switch statement to rerun the statement. (The reevaluation/conditional jump could be optimized away, if the condition is a simple expression.) I'm almost sure i've actually seen this in a real language, but for the life of me i can't remember where.Tapdance
@Tapdance - Yeah, a "state machine" control structure could certainly be devised. But in a traditional procedural language that's so close to "goto" that its tough to wrap my head around what the practical differences would be. Its probably easier to just declare "goto" your state machine control structure :-)Fregger
@T.E.D.: continue can always be replaced with goto label;. The difference (and indeed, the reason for continue at all) is that continue's target is hard-set and consistent -- obviating the need to define a label (read: potentially-arbitrary goto target), and thus to know/care where label appears. But another bonus would reveal itself with a mix of dynamic and static transitions. Suddenly, there's one idiom for both, the code keeps the state info updated (because it defines the target), and yet the compiler can optimize static transitions iff there's a benefit.Tapdance
@PopCatalin The difference is that the other function is not able to access your local variables, so you can prove stuff about them.Hoedown
@Dave, agree,by using functions is easier to prove invariants hold if you don't give those functions access to the local variables, if you do, then there's no difference.Reaves
"refactoring it into a function" with the SOLE purpose of avoiding a goto is absurd. The goal is to make the code more maintainable, and if goto serves that purpose, as it seems to with the poster's answer, then you just do not hide the code into a function unnecessarily.Wavelet
@Cathee "640K ought to be enough for anyone." - Bill GatesPoised
@Poised How is that quote relevant?Pogey
@PCLuddite In response to the Torvalds quote about indentation. The point being you can't blanket condemn something using an appeal to authority, nor assume one size fits all. Sometimes people use more than three levels of nesting, sometimes people use more than 640K, and sometimes people use GOTO.Poised
P
100

Goto is extremely low on my list of things to include in a program just for the sake of it. That doesn't mean it's unacceptable.

Goto can be nice for state machines. A switch statement in a loop is (in order of typical importance): (a) not actually representative of the control flow, (b) ugly, (c) potentially inefficient depending on language and compiler. So you end up writing one function per state, and doing things like "return NEXT_STATE;" which even look like goto.

Granted, it is difficult to code state machines in a way which make them easy to understand. However, none of that difficulty is to do with using goto, and none of it can be reduced by using alternative control structures. Unless your language has a 'state machine' construct. Mine doesn't.

On those rare occasions when your algorithm really is most comprehensible in terms of a path through a sequence of nodes (states) connected by a limited set of permissible transitions (gotos), rather than by any more specific control flow (loops, conditionals, whatnot), then that should be explicit in the code. And you ought to draw a pretty diagram.

setjmp/longjmp can be nice for implementing exceptions or exception-like behaviour. While not universally praised, exceptions are generally considered a "valid" control structure.

setjmp/longjmp are 'more dangerous' than goto in the sense that they're harder to use correctly, never mind comprehensibly.

There never has been, nor will there ever be, any language in which it is the least bit difficult to write bad code. -- Donald Knuth.

Taking goto out of C would not make it any easier to write good code in C. In fact, it would rather miss the point that C is supposed to be capable of acting as a glorified assembler language.

Next it'll be "pointers considered harmful", then "duck typing considered harmful". Then who will be left to defend you when they come to take away your unsafe programming construct? Eh?

Pollinosis answered 5/9, 2008 at 19:5 Comment(7)
Personaly, this is the comment I would have given the check to. One thing I'd like to point out to readers is that the esoteric term "state machines" includes such everyday things as lexical analysers. Check out the output of lex somtime. Full of gotos.Fregger
You can use a switch statement inside of a loop (or event handler) to do state machines just fine. I've done lots of state machines without ever having to use a jmp or goto.Freewheel
+1 Those arrows on state machines map to 'goto' more closely than to any other control structure. Sure, you can use a switch inside a loop -- just like you can use a bunch of gotos instead of a while for other problems, but it's usually a idea; which is the whole point of this discussion.Anastassia
Can I quote you on that last paragraph?Anabelanabella
Sure, I hope you find it useful. I refer you to my user profile: "All my original contributions to StackOverflow are hereby placed into the public domain" :-)Pollinosis
And, here in 2013, we've already hit (and kinda gotten past) the "pointers considered harmful" phase.Penzance
@T.E.D., Re "esoteric"? Implementing small state machines within functions is a common everyday coding problem, absolutely nothing to do with lex nor near-lex code.Malignity
L
98

We already had this discussion and I stand by my point.

Furthermore, I'm fed up with people describing higher-level language structures as “goto in disguise” because they clearly haven't got the point at all. For example:

Even the advanced continuation control structure in Scheme can be described as a sophisticated goto.

That is complete nonsense. Every control structure can be implemented in terms of goto but this observation is utterly trivial and useless. goto isn't considered harmful because of its positive effects but because of its negative consequences and these have been eliminated by structured programming.

Similarly, saying “GOTO is a tool, and as all tools, it can be used and abused” is completely off the mark. No modern construction worker would use a rock and claim it “is a tool.” Rocks have been replaced by hammers. goto has been replaced by control structures. If the construction worker were stranded in the wild without a hammer, of course he would use a rock instead. If a programmer has to use an inferior programming language that doesn't have feature X, well, of course she may have to use goto instead. But if she uses it anywhere else instead of the appropriate language feature she clearly hasn't understood the language properly and uses it wrongly. It's really as simple as that.

Langevin answered 5/9, 2008 at 19:5 Comment(29)
Of course, the proper use of a rock isn't as a hammer. One of its proper uses is a grinding stone, or for sharpening other tools. Even the lowly rock, when used properly is a good tool. You just have to find the proper usage. Same goes for goto.Transversal
So what is the proper use of Goto? For every case imaginable there's another tool better suited. And even your grinding stone is actually replaced by high-tech tools nowadays, even if they are still made of rock. There's a big difference between a raw material and a tool.Langevin
Loop and a half? Non-exceptional (eg, file-not-found) escape to cleanup code? (Exceptions are designed to trade the throw cost for the try cost - independant of language.) There is not always 'the appropriate language feature'.Meticulous
Simon: read my original posting linked above. I counter these arguments there.Langevin
I've yet to see an example of a problem outside of C where goto was the cleanest solution. In C it is a commonly used idiom, but then C was designed as a "portable asm". In C++, you'd certainly never use goto to jump to cleanup code. You use RAII instead. And in C#, goto doesn't exist.Skep
@jalf: Goto most certainly does exist in C#. See #359936Bowers
david.tribble.com/text/goto.htmlMontymonument
@Tim: I know that paper and I find it uninspiring. It lacks substance, side-steps Dijstra's arguments and prefers to tear down straw-men. In particular, my above (short) posting completely dismantles it. Furthermore, the examples at the end ignore existing best practices which solve the issue. SorryLangevin
You hit the nail on the head. With a hammer.Adventurer
As a note I have used rocks as sharpening stones. Works great when you need to sharpen a knife and didn't pack a stone. There are times and places for every tool. There even times you might use a rock to drive something into the ground (say setting up a tent and you don't feel like lugging a hammer around.) Never say never... Also there are times when using the latest tool is not the right choice either. I have seen people take 20 minutes to setup a powersaw to cut something that would of taken less than a minute to do with a hand saw.Icbm
I am dismayed so many people approve of this post. Your post only seemed effective because you never bothered to question what logic you were actually performing, thus you failed to notice your fallacy. Allow me to paraphrase your entire post: "There is a superior tool for a goto in every situation, so gotos should never be used." This is a logical biconditional, and as such your entire post is essentially begging the question "How do you know there is a superior tool for a goto in every situation?"Earmuff
@Coding: No, you completely missed the gist of the posting. It was a riposte rather than an isolated, complete argument. I merely pointed out the fallacy in the main argument “for” goto. You are right in so far as I don’t offer an argument against goto per se – I didn’t intend to – so there’s no question-begging.Langevin
As for your paraphrase, if you read carefully you’ll find that you merely paraphrased my last sentence. And here, your paraphrase is indeed spot-on. But the onus is on you to demonstrate a use for goto, not on me to refute every imaginable use. That’s Russell’s teapot all over. …Langevin
(cont’d) And notice that I did concede uses for goto in languages that lack appropriate language features (e.g. error handling in C) in my posting, hence the rock-on-an-island analogy. But that observation is utterly trivial and doesn’t merit discussion: “Given insufficiently advanced tools, I have to make do with inferior tools.” That statement borders on tautology. – So in conclusion, arguments for goto are language-specific and should not be generalized: Java (say) doesn’t need goto, at least nobody could ever show conclusively that it would be advantageous.Langevin
What of finite state machines? Also, I presume you've not read the article "Structured Programming with go to Statements" by Donald E. Knuth which the OP mentioned?Earmuff
FSMs don’t really benefit from gotos. For example, the loop/switch pattern with a state variable models them much better, at the same cost (and I disagree with Steve Jessop on this one). Tribble’s closing example, the LR parser can be implemented equally elegantly using mutually tail-recursive functions. And yes, I’ve read Knuth’s take on the problem but it’s just completely outdated, even though it was a very good article back then. For example, it makes very hardware-specific assumptions (memory access counts, viz. caching) and compiler optimizations (loop unrolling).Langevin
How does the loop/switch pattern model them better? You're just adding logical steps without improving the readability. And while a lot of Knuth's points are outdated (for instance, endorsing general gotos where modern programming has developed specialized gotos), they're not all inapplicable; take for instance his example 4 under Text Scanning.Earmuff
By the way, the onus may be on us to demonstrate a use for goto, but the onus is on you to refute every demonstrated use.Earmuff
@Coding: Your last sentence is true. But every instance I knew had already been refuted (even if not in this thread) and I grow weary of the discussion. Which is why I have not taken part here, except to point out one fallacy. FYI, example 4 can be made easier and (IMHO) much clearer by using a lookahead to peek at the next character without consuming it. Additionally, I prefer solution 4a, I disagree with its alleged difficulty and it obviously renders goto unnecessary here. – Finally, I can’t answer your concern about my FSMs since I don’t see what logical steps I’m supposedly adding.Langevin
On FSMs: The goto jumps to the label. The loop/switch sets a flag, jumps past the end of the switch, jumps back to the top of the loop, tests (true), tests the flag until it reaches the right case, then jumps to the less descriptive label-the case statement. I fail to understand how that is superior to the goto version. You merely rely on the compiler to optimize away the logical inefficiencies you introduced, but you still leave the program with more to keep track of (like the variable your switch checks) and the reader with reader with more work to do to understand your finite state machine.Earmuff
And on Example 4, regardless of your preference, Knuth is absolutely correct here: By adding the variable, the entire routine now needs to reserve memory for an additional boolean, check the new "double slash" boolean every time it is to write a character, and the boolean "double slash" is more ambiguous in purpose to the reader than the "go to char processed;" Consequently, example 4a is both less efficient, and it makes the code harder to follow.Earmuff
On FMS: while (true) is a stupid test. while(not eof()) on the other hand makes a lot more sense. And the “state” makes the automaton state explicit (stored in a variable), rather than having it implicit in the current program state (instruction pointer). At the very least, this makes debugging easier. And a switch for me as a reader implies direct jumping to the correct label, not subsequent testing, so I see no mental overhead at all. This is exactly like I execute FSMs manually on paper. As for ex4, well, I disagree with your unproven assertion (“ambiguous”). Where does this leave us?Langevin
@Coding With Style: I never talked about object orientation.Langevin
Wow, my mind must have been somewhere else for a moment. Sorry about that. :-( Here's the fixed version below.Earmuff
On the state variable: How does it make debugging easier? Why is this worth the added overhead? You still haven't pointed out what makes your approach better as opposed to merely alternative. And on ex4, the ambiguity originates from the fact that with a boolean you only know it will be tested somewhere, but with the goto you immediately know exactly what happens.Earmuff
(1 of 3) I argue that there's nuance in everything. Just like how switch statements can be godawful and are typically a code smell indicating poor structure or tight coupling, using goto for control flow is a definite code smell, except when it's not. If used correctly, gotos are a powerful tool for making code more readable. It's hard to create spaghetti code if your gotos have obvious names and only ever jump forward.Parodic
(2 of 3) My rules for using goto are as follows: 1. the label should be named descriptively, e.g. exit_io_error. 2. labels should do exactly what their name implies, then exit the function, and nothing else (especially not another goto). 3. like putting variables at the top of their scope, labels should be grouped together at the bottom of their respective function. There is a clear separation of header, code, and footerParodic
(3 of 3) This actually makes code more comprehensible, reduces clutter, and makes it possible to expand these labels later on, e.g. with an stderr printout of what went wrong, or cleanup that you'd otherwise be repeating by avoiding goto. In languages with exception objects, of course you should use throw and catch, but C is not one of those languages, nor is it "inferior", for that matter.Parodic
When used properly, gotos are like inlined functions that share the scope of the current function. Which isn't a problem so long as they are well-named and organized, because nobody reads the entire thing at once. What you see is something like if(bufsz > MAX_BUFSZ) goto exit_toobig;, which is plainly obvious in the same way that ch = getchar() is plainly obvious. What does it do? It gets a char. That's it. You know what it does. Not how, but that doesn't matter if you're just reading the code. And when it does matter, it's easy to find out.Parodic
S
78

In Linux: Using goto In Kernel Code on Kernel Trap, there's a discussion with Linus Torvalds and a "new guy" about the use of GOTOs in Linux code. There are some very good points there and Linus dressed in that usual arrogance :)

Some passages:

Linus: "No, you've been brainwashed by CS people who thought that Niklaus Wirth actually knew what he was talking about. He didn't. He doesn't have a frigging clue."

-

Linus: "I think goto's are fine, and they are often more readable than large amounts of indentation."

-

Linus: "Of course, in stupid languages like Pascal, where labels cannot be descriptive, goto's can be bad."

Spirit answered 5/9, 2008 at 19:5 Comment(12)
That's a good point how? They are discussing its use in a language which has nothing else. When you're programming in assembly, all branches and jumps are goto's. And C is, and was, a "portable assembly language". Moreover, the passages you quote say nothing about why he thinks goto is good.Skep
Wow. That's disappointing to read. You'd think a big OS guy like Linus Torvalds would know better than to say that. Pascal (old-school pascal, not the modern Object version) was what Mac OS Classic was written in during the 68k period, and it was the most advanced operating system of its time.Barbabra
rummages through the link I guess if you are coding in C, GOTO is more useful. But if you're in a modern language which supports exceptions...Outlaw
@mason Classic Mac OS had some Pascal libraries (eventually -- the Pascal runtime took up too much memory in the early Macs) but the majority of the core code was written in Assembler, particularly the graphics and UI routines.Vetter
@Jim: QuickDraw was originally written in Pascal for the Lisa, which had more hardware and could handle the runtime. The same code was basically copied wholesale for the Mac, except that it had to be optimized in assembly due to memory requirements. It was still Pascal code; it was just compiled by hand. ;)Barbabra
Yes, Linus is an arrogant SOB... never mind that pesky little contribution to the entire IT industryRejoice
Linus only argues (explicitly, like Rik van Riel in that discussion) for goto for handling exit status, and he does so on the basis of the complexity that C's alternative constructs would bring if they were used instead.Edmee
@MarkJ: +1 for -1'ing a person.Warpath
IMHO Linus is right on this issue. His point is that kernel code, written in C, that needs to implement something similar to exception handling, is most clearly and simply written by using a goto. The idiom goto cleanup_and_exit is one of the few "good" uses of goto left now that we have for, while, and if to manage our control flow. See also: programmers.stackexchange.com/a/154980Radiolocation
Also, Pascal was originally designed as a teaching language. It's a little bit easier to write a Pascal compiler since goto labels are unsigned integers. And, since Pascal has if and for and while, Niklaus Wirth likely wasn't expecting goto to be used much! Out in the real world, descriptive names are the way to go, which is one of the reasons C is a better language than Pascal for writing operating systems kernels.Radiolocation
@jalf, C is absolutely relevant in today's world. How is it not a good point?Malignity
Co-routines/Iterators/Generators/Higher-order functions/Exceptions are also good uses of the goto... Bad use of gotos = inheritance.Kleon
T
56

Today, it's hard to see the big deal about the GOTO statement because the "structured programming" people mostly won the debate and today's languages have sufficient control flow structures to avoid GOTO.

Count the number of gotos in a modern C program. Now add the number of break, continue, and return statements. Furthermore, add the number of times you use if, else, while, switch or case. That's about how many GOTOs your program would have had if you were writing in FORTRAN or BASIC in 1968 when Dijkstra wrote his letter.

Programming languages at the time were lacking in control flow. For example, in the original Dartmouth BASIC:

  • IF statements had no ELSE. If you wanted one, you had to write:

    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
    
  • Even if your IF statement didn't need an ELSE, it was still limited to a single line, which usually consisted of a GOTO.

  • There was no DO...LOOP statement. For non-FOR loops, you had to end the loop with an explicit GOTO or IF...GOTO back to the beginning.

  • There was no SELECT CASE. You had to use ON...GOTO.

So, you ended up with a lot of GOTOs in your program. And you couldn't depend on the restriction of GOTOs to within a single subroutine (because GOSUB...RETURN was such a weak concept of subroutines), so these GOTOs could go anywhere. Obviously, this made control flow hard to follow.

This is where the anti-GOTO movement came from.

Theodosia answered 5/9, 2008 at 19:5 Comment(3)
Another thing to note is that the preferred way of writing code if one had some code in a loop which would have to execute rarely would be 420 if (rare_condition) then 3000 // 430 and onward: rest of loop and other main-line code // 3000 [code for rare condition] // 3230 goto 430. Writing code that way avoids any taken branches or jumps in the common main-line case, but it does make things hard to follow. Branch avoidance in assembly code can be worse, if some branches are limited to e.g. +/- 128 bytes and sometimes don't have complementary pairs (e.g. "cjne" exists but not "cje").Bennie
I once wrote some code for the 8x51 which had an interrupt that ran once every 128 cycles. Every extra cycle spent in that ISR's common case would reduce the execution speed of mainline code by more than 1% (I think about 90 cycles out of 128 were usually available to the main-line), and any branching instruction would take two cycles (in both branching and fall-through cases). The code had two comparisons--one which would usually report equal; the other, not-equal. In both cases, the rare-case code was more than 128 bytes away. So...Bennie
cjne r0,expected_value,first_comp_springboard /.../ cjne r1,unexpected_value,second_comp_fallthrough // ` ajmp second_comp_target` // first_comp_springboard: ajmp first_comp_target // second_comp_fallthrough: .... Not a very nice coding pattern, but when individual cycles count, one does such things. Of course, in the 1960's, such levels of optimization were more important than today, especially since modern CPUs often require weird optimizations, and just-in-time compile systems may be able to apply optimize code for CPUs that didn't exist when the code in question was written.Bennie
H
53

In C, goto only works within the scope of the current function, which tends to localise any potential bugs. setjmp and longjmp are far more dangerous, being non-local, complicated and implementation-dependent. In practice however, they're too obscure and uncommon to cause many problems.

I believe that the danger of goto in C is greatly exaggerated. Remember that the original goto arguments took place back in the days of languages like old-fashioned BASIC, where beginners would write spaghetti code like this:

3420 IF A > 2 THEN GOTO 1430

Here Linus describes an appropriate use of goto: http://www.kernel.org/doc/Documentation/CodingStyle (chapter 7).

Heresiarch answered 5/9, 2008 at 19:5 Comment(8)
When BASIC was first available, there wasn't any alternative to GOTO nnnn and GOSUB mmmm as ways to jump around. Structured constructs were added later.Arian
You're missing the point... even then you didn't have to write spaghetti... your GOTOs could always be used in a disciplined mannerRejoice
It's also worth noting that the behavior of setjmp/longjmp was only specified when they were used as a means of jumping to a spot within a scope from other places within that same scope. Once control leaves the scope where setjmp is executed, any attempt to use longjmp on the structure created by setjmp will result in undefined behavior.Bennie
Some versions of BASIC would let you do GOTO A * 40 + B * 200 + 30. It's not hard to see how this was very handy, and very dangerous.Splenetic
Didn't GOSUB come out some time after BASIC first came out?Renayrenckens
@JonHanna What the heck would that even mean?! When would that be handy? Do you have any link to more info about those BASIC dialects?Datary
@Datary it would compute the expression and then go to the line of code with that number (explicit line numbers was a requirement of most earlier dialects). ZX Spectrum Basic was one that would accept thatSplenetic
@JonHanna Aha, now I feel stupid. I read it as (GOTO A) * 40 + B * 200 + 30 and was super confused, what would GOTO in the middle of an expression do? I guess I've been writing too much Haskell (which uses whitespace for function application) lately. :PDatary
H
36

Go To can provide a sort of stand-in for "real" exception handling in certain cases. Consider:

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;

Obviously this code was simplified to take up less space, so don't get too hung up on the details. But consider an alternative I've seen all too many times in production code by coders going to absurd lengths to avoid using 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);

Now functionally this code does the exact same thing. In fact, the code generated by the compiler is nearly identical. However, in the programmer's zeal to appease Nogoto (the dreaded god of academic rebuke), this programmer has completely broken the underlying idiom that the while loop represents, and did a real number on the readability of the code. This is not better.

So, the moral of the story is, if you find yourself resorting to something really stupid in order to avoid using goto, then don't.

Hirsch answered 5/9, 2008 at 19:5 Comment(3)
Although I tend to agree with what you're saying here, the fact that the break statements are inside a control structure makes clear exactly what they do. With the goto example, the person reading the code has to look over the code to find the label, which in theory, could actually be before the control structure. I'm not experienced enough with old-style C to make a judgement that one is definitely better than the other, but there are trade-offs either way.Cepeda
@DanielAllenLangdon: The fact that the breaks are inside a loop makes clear exactly that they exit the loop. That's not "exactly what they do", since in reality, there's not a loop at all! Nothing in it ever has a chance of repeating, but that's not clear til the end. The fact that you have a "loop" that never runs more than once, means that control structures are being abused. With the goto example, the programmer can say goto error_handler;. It is more explicit, and even less difficult to follow. (Ctrl+F, "error_handler:" to find the target. Try doing that with "}".)Tapdance
I once saw code similar to your second example in an air traffic control system - because 'goto is not in our lexicon'.Duplessismornay
A
32

Donald E. Knuth answered this question in the book "Literate Programming", 1992 CSLI. On p. 17 there is an essay "Structured Programming with goto Statements" (PDF). I think the article might have been published in other books as well.

The article describes Dijkstra's suggestion and describes the circumstances where this is valid. But he also gives a number of counter examples (problems and algorithms) which cannot be easily reproduced using structured loops only.

The article contains a complete description of the problem, the history, examples and counter examples.

Albion answered 5/9, 2008 at 19:5 Comment(0)
N
30

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.

Neglect answered 5/9, 2008 at 19:5 Comment(3)
I can't wait for "manual memory management considered harmful". but we don't speak against the "church of C"Cantle
@LuizFelipe The first half of your comment makes sense to me: excessively manual memory management is a big practical problem, indeed. However, I do not understand your quoted remark about the "church of C." As far as I know, the C programming language survives and prospers because it is small and does well that which it was designed to do: to act as a portable assembler. C++ and Rust do it better, of course, but they are not small.Neglect
Did you ever read the C11 standard? C is not small.Cantle
A
27

Attracted by Jay Ballou adding an answer, I'll add my £0.02. If Bruno Ranschaert had not already done so, I'd have mentioned Knuth's "Structured Programming with GOTO Statements" article.

One thing that I've not seen discussed is the sort of code that, while not exactly common, was taught in Fortran text books. Things like the extended range of a DO loop and open-coded subroutines (remember, this would be Fortran II, or Fortran IV, or Fortran 66 - not Fortran 77 or 90). There's at least a chance that the syntactic details are inexact, but the concepts should be accurate enough. The snippets in each case are inside a single function.

Note that the excellent but dated (and out of print) book 'The Elements of Programming Style, 2nd Edn' by Kernighan & Plauger includes some real-life examples of abuse of GOTO from programming text books of its era (late-70s). The material below is not from that book, however.

Extended range for a DO loop

       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

One reason for such nonsense was the good old-fashioned punch-card. You might notice that the labels (nicely out of sequence because that was canonical style!) are in column 1 (actually, they had to be in columns 1-5) and the code is in columns 7-72 (column 6 was the continuation marker column). Columns 73-80 would be given a sequence number, and there were machines that would sort punch card decks into sequence number order. If you had your program on sequenced cards and needed to add a few cards (lines) into the middle of a loop, you'd have to repunch everything after those extra lines. However, if you replaced one card with the GOTO stuff, you could avoid resequencing all the cards - you just tucked the new cards at the end of the routine with new sequence numbers. Consider it to be the first attempt at 'green computing' - a saving of punch cards (or, more specifically, a saving of retyping labour - and a saving of consequential rekeying errors).

Oh, you might also note that I'm cheating and not shouting - Fortran IV was written in all upper-case normally.

Open-coded subroutine

       ...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

The GOTO between labels 76 and 54 is a version of computed goto. If the variable i has the value 1, goto the first label in the list (123); if it has the value 2, goto the second, and so on. The fragment from 76 to the computed goto is the open-coded subroutine. It was a piece of code executed rather like a subroutine, but written out in the body of a function. (Fortran also had statement functions - which were embedded functions that fitted on a single line.)

There were worse constructs than the computed goto - you could assign labels to variables and then use an assigned goto. Googling assigned goto tells me it was deleted from Fortran 95. Chalk one up for the structured programming revolution which could fairly be said to have started in public with Dijkstra's "GOTO Considered Harmful" letter or article.

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).

Arian answered 5/9, 2008 at 19:5 Comment(2)
If you want to see an example of some code using goto 'in the wild', the question Wanted: Working Bose-Hibbard Sort Algorithm shows some (Algol 60) code published in 1963. The original layout doesn't compare to modern coding standards. The clarified (indented) code is still fairly inscrutable. The goto statements there do make it (very) hard to understand what the algorithm is up to.Arian
Being too young to have experienced anything close to punch cards, it was enlightening to read about the re-punching problem. +1Dorie
S
20

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 compiler 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.

Scribner answered 5/9, 2008 at 19:5 Comment(6)
The problem with GOTO is that it breaks important invariants that we take for granted with modern programming languages. To take one example, if I call a function, we assume that when the function completes, it will return control to the caller, either normally, or via exceptional stack unwinding. If that function mis-uses GOTO, then of course this is no longer true. This makes it very hard to reason about our code. It is not sufficient to carefully avoid the mis-use of GOTO. The problem still occurs if GOTO is misused by our dependencies...Klee
... So in order to know whether we can reason about our function calls, we need to examine every line of the source code of every one of our transitive dependencies, checking that they do not misuse GOTO. So just the existence of GOTO in the language has broken our ability to confidently reason about our own code, even if we use it perfectly (or never use it) ourselves. For this reason, GOTO is not just a tool to be used carefully. It is systemically broken and its existence in a language is unilaterally considered harmful.Klee
Even if the goto keyword was scrubbed from C#, the concept of "jump here" still exists in IL. An infinite loop can easily be constructed without the goto keyword. If this lack of guarantee that the called code will return, in your opinion, means "unable to reason about the code", then I'd say we never had that ability.Scribner
Ah, you have insightfuly found the source of our miscommunication. The goto in C# is not a real "goto" in the original sense of the word. It is a much weaker version that only allows for jumping within a function. The sense in which I'm using "goto" allows for jumping anywhere in process. So although C# has a "goto" keyword, it arguably has never had, a real goto. Yes, a real goto is available at IL level, in the same way that it is when any language is compiled down to assembly. But the programmer is shielded from that, unable to use it under normal circumstances, so it doesn't count.Klee
Incidentally, the opinion I'm describing here is not originally mine, but is the core of Dijkstra's original paper from 1967 I think, re-titled by his editor "Goto considered harmful", which has become such an oft-quoted meme for 50 years precisely because it was so revolutionary, insightful, and universally accepted.Klee
And you are right to raise the example of infinite loops as functions that never return. This is, obviously enough, the very essence of Turing's halting problem, which demonstrated that code which contains such things, just as you say, cannot be successfully reasoned about. So let's assume this whole conversation is about well-formed programs, that do not contain infinite loops. That is why I carefully phrased my original statement as "when the function completes"Klee
A
18

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 -- e.g. 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.)

Adhern answered 5/9, 2008 at 19:5 Comment(0)
T
17

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

Tmesis answered 5/9, 2008 at 19:5 Comment(0)
G
16

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 gotos, 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 ifs 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".

Girasol answered 5/9, 2008 at 19:5 Comment(1)
+1 for annoying the purists! :-)Clarettaclarette
M
15

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(stride) goto *(opcodes[*(pc += stride)])
    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.

Malissamalissia answered 5/9, 2008 at 19:5 Comment(4)
Only problem, that it's not standard, is it?Fourlegged
&&op_inc certainly does not compile, because (the left) & expects an lvalue, but (the right) & yields an rvalue.Anthracene
@FredO: It's a special GCC operator. However, I'd reject this code in all but the direst of circumstances, because I most assuredly cannot understand wtf's going on.Factious
While this is one example (max. optimization for speed) that justifies both the use of goto's and the cryptic code, it should still be highly commented to explain the need for optimization, roughly how it works, and the best line-by-line comments that can be made. So, it still fails, but because it leaves maintenance programmers in the dark. But I DO like the VM example. Thanks.Dot
B
12

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
Billman answered 5/9, 2008 at 19:5 Comment(3)
DO CRT 'Is this correct? (Y/N) : ': INPUT YORN UNTIL YORN = 'Y' OR YORN = 'N'; etc.Spillage
Indeed, but more importantly, a real programmer knows when not to use a goto - and knows why. Avoiding a taboo language construct because $programming_guru said so, that's the very definition of cargo-cult programming.Capet
It's a good analogy. To drive a nail without damaging the substrate, you don't eliminate the hammer. Rather, you use a simple tool known as a nail punch. This is a metallic pin with a tapered end that has a hollow indentation at its tip, to securely couple with the nail head (these tools come in different sizes for different nails). The other, blunt end of the nail punch is struck with a hammer.Wed
A
9

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

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

Amur answered 5/9, 2008 at 19:5 Comment(1)
+1 for 'eliminating the goto introduced a bug'Duplessismornay
H
7

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.

Humpbacked answered 5/9, 2008 at 19:5 Comment(0)
S
7

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

Surfing answered 5/9, 2008 at 19:5 Comment(0)
I
6

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 trivial
{
    // 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 trivial
{
    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

Indefatigable answered 5/9, 2008 at 19:5 Comment(3)
The non-GOTO way would be to use a fast_calculations function, which incurs some overhead. Probably not noticeable in most circumstances, but as you said this was speed-critical.Dream
Well that is hardly surprising. All code that has absolutely insane performance guidelines will always break pretty much all best-practices. Best practices are for reachability, and maintainability, not for squeezing out 10 more milliseconds or saving 5 bytes more ram.Foremost
@JonathonWisnoski, legitimate uses of goto also eliminate insane amounts of spagetti code meddling with a rat's nests of variables to keep track where we are going.Opportune
F
6

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.

Frazier answered 5/9, 2008 at 19:5 Comment(0)
P
5

If GOTO itself were evil, compilers 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 intricate 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? Yes. Does it take some learning on the part of the maintainer? Yes. Does that learning pay off? I think so. Could it be done without GOTOs that jump into blocks? Nope.

Petronilapetronilla answered 5/9, 2008 at 19:5 Comment(1)
Avoiding a language feature out of fear is a sign of brain damage. This is also niftier than hell.Carthage
G
5

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

Grisaille answered 5/9, 2008 at 19:5 Comment(2)
So labeled break or continue would be different from goto how?Icbm
They don't permit totally arbitrary jumps in control flow.Grisaille
P
4

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.

Pattison answered 5/9, 2008 at 19:5 Comment(3)
The nice thing about Try...Catch blocks in C# is that they take care of cleaning up the stack and other allocated resources (called unwinding the stack) as the exception bubbles up to an exception handler. This makes a Try...Catch much better than Goto, so if you have Try...Catch, use it.Freewheel
I have a better solution: wrap the chunk of code you want to pop out of in a 'do { ... } while (0);' loop. That way, you can jump out in the same manner as a goto without the overhead of the try/catch loop (I don't know about C#, but in C++ try is low-cost & catch is high-cost, so it seems excessive to throw an exception where a simple jump would suffice).Vetter
Jim, the problem with that is that it's nothing more than a stupidly roundabout way of obtaining a goto.Earmuff
B
4

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

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

Berthaberthe answered 5/9, 2008 at 19:5 Comment(6)
Who exactly do you think creates the compilers?Caracaraballo
Compilers, of course!Spinning
I think he means "GOTO is something that should only be used by code emitted by a compiler".Meticulous
This is a case against goto. Where we might use goto in a state-machine coded by hand to implement an enumerator, we can just use yield instead.Splenetic
switch on many string (to prevent compile to if-else) with default case compiles to switch with goto statement.Mortarboard
Obfuscators need goto.Napier
M
4

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

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

Magdaleno answered 17/6, 2010 at 7:41 Comment(0)
B
3

C++ contains constructors and destructors. This allows for a pattern know as RAII (resource allocation is initialization). Basically, you create a local stack variable, and the act of creating the stack variable opens a file, allocates memory, locks a mutex, or otherwise acquires a resource that must later be released.

When the variable goes out of scope, the destructor runs and frees the resource.

C doesn't have this feature. But you still often need to acquire resources at the beginning of a function, and release them at the end.

Your function probably has one or more error conditions that cause it to return early. You don't want to duplicate the resource release code. The solution is to use goto.

Example:

int
foo(const char *arg)
{
    char *argcopy = strdup(arg);

    if (!isvalid(argcopy))
        goto out1;

    FILE *myfile = fopen(argcopy, "r");
    if (myfile == NULL)
      goto out1;

    char bytes[10];
    if (fread(bytes, sizeof(bytes), 1, myfile) != sizeof(mybytes))
        goto out2;

    /* do some actual work */
    /* .... */
    /* end of actual work */

    out2:
    fclose(myfile);

    out1:
    free(argcopy);

    return 0;
 }
Bismarck answered 5/9, 2008 at 19:5 Comment(0)
R
3

Yes, GOTO is still considered harmful. By the time you find yourself in the rare situation where the use of a GOTO might be valid, you should be confident enough in your own programming skill not to need the validation of others. Any GOTO-like functions that allow you to jump even farther away in scope than allowed by GOTO should be considered more dangerous than GOTO.

Roque answered 5/9, 2008 at 19:5 Comment(0)
S
3

GOTO is like a table saw, extremely useful when appropriate safety measures are taken.

I consider it harmful, because most beginners lose fingers with both table saws, and GOTOs.

There are some situations where its the only way to control flow, but those situations can be avoided.

Schleswig answered 5/9, 2008 at 19:5 Comment(9)
"most beginners loose fingers with both table saws, and GOTO" -- rubbish. I have all of my fingers and I've made good use of both. Gotos, like tablesaws, are sometimes the right tool for the job. Trying to shoehorn some other tool into its role will usually cause greater risk and lesser quality. ("Avoiding" the situation is the same thing.)Sophistry
Clearly you are not most. I've never lost fingers to them either. Although I seen plenty of halved digits from table saws, and plenty of bugs in systems from goto's. I've honestly never seen a GOTO in a modern OO language that was required, for the business that commissioned that software to make money.Schleswig
I'll agree that in many higher level languages goto is largely, if not entirely, replaced by more powerful/specialized tools. The root problem doesn't go away though (e.g. exceptions can also be dangerous in the hands of the undisciplined). Any tool will require that you learn how to (and do!) use it properly.Sophistry
Tangentially, table saws are not as dangerous as you make them sound. I'm pretty sure nobody in my middle/high-school shop classes got hurt with a tablesaw (though there were a few accidents with other tools...). Most people (even beginners) don't get hurt on them.Sophistry
so lets take a side step, table saws are touted generally as the most dangerous wood working tool. GOTOs have also been widely known to inflict harm. Personally a simple function can replace a goto. The point is, there is no real reason you should choose goto over something less dangerous. The wood working analogy breaks down here, because the table saw has no less dangerous analog.Schleswig
"the table saw has no less dangerous analog" -- I'd say the table saw is the less dangerous analog. There are plenty of more dangerous saws. Let's compare goto to a circular saw instead. It can do pretty much everything a table saw can do. But you also have to be more careful -- a circular saw can grab on the piece you are cutting and kick back into you (quite possibly opening up your femoral artery) if you don't take care. On the other hand, you can't haul most table saws onto a job site, and there are certain types of cuts for which a circular saw is better suited than a table saw.Sophistry
Similarly, function calls are not as versatile as gotos. One example where goto is useful is an efficient state machine -- no call stack overhead, no worries about recursion, no extra state variables, and the flow is about as obvious state machines get without specialized constructs. Another classic example is local error handling in a C function, especially for a sequence of memory allocations. Stick deallocations at the end with labels, and if any allocation (or other operation) fails, you jump to the correct label, and everything that's already been allocated gets cleaned up properly.Sophistry
It's really just a matter of using the right tool for the job. And I definitely agree that goto is usually not the right tool for the job. But if you dismiss it entirely, you limit your capabilities unnecessarily. Don't throw out that slot screwdriver just because it's a stupid design -- sometimes you need it anyway.Sophistry
If you think gotos are bad you must also agree that inheritance and especially threads are bad and worse, and action at a distance mutability. Gotos only exist for one method. Goto can be used to implement co-routines, higher-order functions, iterators, generators, all kind of stuff that we forgot about in the early C days.Kleon
O
3

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.

Obese answered 5/9, 2008 at 19:5 Comment(0)
S
2

goto can be useful, here is an example of very strong open-source chess engine stockfish written in c++. The goto just skips some conditions checking (efficiency gain) that the program would have to do if not for the goto statement. If the goto statement label is after the goto declaration, then they are pretty harmless and readable.

Sonya answered 5/9, 2008 at 19:5 Comment(1)
I'm sure gotos can be useful, but in the case of this example I think it's more of a symptom of the larger problem that we're having to navigate a 700 line function.Babita
R
2

While I think it's best to avoid goto on almost any situation, there are exceptions. For example, one place I've seen where goto statements are the elegant solution compared to others much more convoluted ways is implementing tail call elimintation for an interpreter.

Retort answered 5/9, 2008 at 19:5 Comment(0)
B
2

On every platform I have seen, high level control structures are implemented as low level gotos (jumps). For example, the Java Virtual Machine has a Jump byte code, but nothing for if, else, while, for, etc.

And some of these compilers create spaghetti code for a simple conditional block.

To answer your question, goto is still considered harmful by people who believe it to be harmful. Goto makes it easy to lose the advantages of structured programming.

In the end, it's your program; and therefore your decision. I suggest not using goto until you are able to answer your question yourself, but in the context of a specific problem.

Brewer answered 5/9, 2008 at 19:5 Comment(1)
When you get down to the machine code, goto is the only way to get anywhere. Of course it will turn up more the closer you get. The question is is it harmful in code that is programmer-written, not compiler-generated.Caracaraballo
P
2

It's not that goto in of itself is bad; it's that using goto when the same logic can be more clearly expressed in another way is bad. It can make the code very hard to follow and makes maintenance hard. Just go and look at some programs in Basic from the Bad Old Days as an example.

In my opinion, in a modern language like C# we should never have a need for goto in normal circumstances. If I find myself using it, it's usually a sign that I need to rethink my logic --- there's almost certainly a clearer way of expressing the same code using normal code flow statements.

That said, there are special purposes for which goto can be extremely useful (and I find myself getting annoyed at languages that don't have it). I mostly use it in C for breaking out of multiple levels of loops, or for error handling; I believe that C# has language features that mean you don't have to do this. (It's also really useful when producing autogenerated code, but that's not something most people encounter in real life.)

There's also another problem with goto, which is purely political: a lot of people hate it, and using it in code, even if justified, may cause issues. If this is assignment code, then yes, rewrite it, or you're likely to get marked down. Otherwise I'd be inclined to leave it in until the next time you need to do maintenance on that section.

Polycrates answered 9/8, 2010 at 21:8 Comment(0)
Q
1

In my opinion, 'goto being harmful' is more about encapsulation and consistency of state than anything else.

Much code, even 'oo' code, has as bad messy state encapsultation as any spaghetti code ever did.

The problem with 'goto considered harmful' is that it leaves the programmer who only looks at the mechanistic rule without the understanding the impression that the only flow control that should be available is the return method, and that very easily leads to passing much state around by reference - and that leads right back to a lack of state encapsulation, the very thing that 'goto considered harmful' was trying to get rid of.

Follow the flow of control in a typical 'OO' codebase, and tell me that we don't still have spaghetti code.... (btw, I don't mean the 'ravioli' code that usuall gets so much hate - the path of execution of ravioli code is usually pretty straightforward, even if the object relationships aren't immediately obvious).

Or, to put it a different way, avoiding gotos in favor of everything being a subroutine is only useful if each subroutine only modifies local state, that cannot be modified except via that subroutine (or at least that object).

Quenby answered 5/9, 2008 at 19:5 Comment(0)
W
1

Many modern programming languages use their compiler to enforce restrictions on the usage of GOTO - this cuts down on the potential risks. For example, C# will not allow you to use GOTO to jump into the body of a loop from outside of it. Restrictions are mentioned in the documentation.

This is one example of how GOTO is sometimes safer than it used to be.

In some cases the use of GOTO is the same as returning early from a function (i.e. to break out of a loop early). However good form can be argued.

Waverly answered 5/9, 2008 at 19:5 Comment(0)
V
1

Once, early in my programming life, I produced a program that consisted of a series of functions in a chain, where each function called its successor given successful conditions and completions.

It was a hideous cludge that had multiple serious problems, the most serious being that no function could terminate until all the functions under it had terminated.

But it was quickly developed, worked well for the limited set of problems it was designed to solve, and was showed the logic and flow of the program explicitly, which worked well when I refactored and extended it for inclusion in another project.

My vote's on use it when it makes sense, and refactor it out as soon as its convenient.

Veator answered 5/9, 2008 at 19:5 Comment(0)
P
1

Using a goto makes it far too easy to write "spaghetti code" which is not particularly maintainable. The most important rule to follow is to write readable code, but of course it depends on what the goals of the project are. As a "best practice" avoiding a goto is a good idea. It's something extreme programming types would refer to as "code smell" because it indicates that you may be doing something wrong. Using a break while looping is remarkably similar to a goto, except it isn't a goto, but again is an indication that the code may not be optimal. This is why, I believe, it is also important to not find more modern programming loopholes which are essentially a goto by a different name.

Panada answered 5/9, 2008 at 19:5 Comment(0)
B
1

I only have the need for it in Basic (ie. VB, VBScript, etc.) and batch files. I then only use it for error handling. In Basic I tend only use the "on error goto". In batch files I have to use it because there isn't an else command. I then only use them as forward jumps to meaningful labels.

Birgit answered 5/9, 2008 at 19:5 Comment(0)
G
1

There are a few issues with goto. One is that it is difficult to see how the code flows. It is easier to see an if-block because of the curly braces, but a goto hides that from you. Also, while and if are also essentially gotos, but they help explain why you are jumping back and forth in your code. With a regular goto that you have to piece together yourself.

As an excercise try writing some code for calculating the fibonacci sequence and see how hard it is to read when you are done.

If you are going to be working on that code then I would recommend writing some unittests and rewriting it. Otherwise, just let it be.

All that said, sometimes, for performance reasons, it 'may' be appropriate to use a goto.

Goodsized answered 9/8, 2010 at 20:53 Comment(0)
H
0

Example of jump in Java String class source code:

int firstUpper;

/* Now check if there are any characters that need to be changed. */
scan: {
    for (firstUpper = 0 ; firstUpper < count; ) {
         char c = value[offset+firstUpper];
         if ((c >= Character.MIN_HIGH_SURROGATE) &&
                 (c <= Character.MAX_HIGH_SURROGATE)) {
             int supplChar = codePointAt(firstUpper);
             if (supplChar != Character.toLowerCase(supplChar)) {
                  break scan;
             }
             firstUpper += Character.charCount(supplChar);
         } else {
             if (c != Character.toLowerCase(c)) {
                  break scan;
             }
             firstUpper++;
         }
     }
     return this;
}
[... subsequent use of firstUpper ...]

this could be rewritten with very little overhead for instance as:

 int firstUpper = indexOfFirstUpper();
 if (firstUpper < 0) return this; 

Even in modern languages, and even if I don't actually like the use of gotos but I consider those acceptable in many cases, in a low-level case like this one looks better to me (and it does a little more than just exiting the loop).

No intention to reanimate a religion war.

Hertahertberg answered 5/9, 2008 at 19:5 Comment(0)
F
0

In a perfect world we would never need a GOTO. However, we live in an imperfect world. We don't have compilers with every control structure we can dream of. On occasion I feel it's better to use a GOTO than kludge a control structure that doesn't really exist.

The most common (not that it's common) is the loop and a half construct. You always execute the first part, maybe you execute the rest of it and then go back and do the first part again. Sure, you can implement it with a boolean flag inside a while loop but I don't like this answer because it's less clear in my opinion. When you see something like:

loop:
  GetSomeData;
  if GotData then
     Begin
        ProcessTheData;
        StoreTheResult;
        Goto Loop;
     End;

to me it's clearer than

Repeat
  GetSomeData;
  Flag := GotData;
  if Flag then
    Begin
      ProcessTheData;
      StoreTheResult;
    End;
Until Not Flag;

and there are times where

Function GotTheData;

Begin
  GetSomeData;
  Result := GotData;
End;

While GotTheData do
  Begin
    ProcessTheData;
    StoreTheResult;
  End;

isn't a workable answer, and I'm a firm believer that code should be clear. If I have to make a comment explaining what the code is doing I consider whether I could make the code clearer and get rid of the comment.

Flavin answered 5/9, 2008 at 19:5 Comment(0)
A
0

Using a GOTO can be nice when you are generating C state machines. I would never use a GOTO in hand-written code - "modern" language constructs make it utterly unnecessary.

The setjmp/longjmp construct can be useful in certain circumstances (when "true" exceptions are missing, or when you are implementing something like Chicken scheme), but it has no place in "ordinary" programming.

Archegonium answered 5/9, 2008 at 19:5 Comment(0)
G
0

Computed gotos for dispatch, often is easyer to understand than a very large switch statement.

For errors and co-threads I think setcontex or setjmp (where available) are 'better'.

Grandeur answered 5/9, 2008 at 19:5 Comment(0)
I
0

Look this, it's a good usse of GoTo, but in a language with garbage collector I think the only reason to use GoTo is to obfuscate your code (obfuscators tools use GoTo to hide their code)

Intelsat answered 5/9, 2008 at 19:5 Comment(0)
H
0

The basic idea is that goto gives you too much freedom to do something you didn't intend to. It can cause errors in places that don't appear to be related to the goto statement, so it makes code maintenance more difficult. If you think you need a goto statement, you're wrong :) and you should instead rethink your code construction. This is why modern programming languages have put alot of effort into giving you readable, maintainable flow control constructs, and exception handling mechanisms.

I'm also going to disagree with lassevk. Since goto is abused more than correctly used, I believe it has no place in a well designed language. Even for goto's "ideal" uses, the other ways of doing it which require more code should be preferred.

So in summary, yes it is still considered harmful.

Hixon answered 5/9, 2008 at 19:5 Comment(1)
Wait, I'm supposed to prefer inferior solutions in my code because somebody else can't exercise discipline?Sophistry

© 2022 - 2024 — McMap. All rights reserved.