views:

1955

answers:

21
+16  Q: 

'goto' usage

I've long been under the impression that 'goto' should never be used if possible. While perusing libavcodec (which is written in C) the other day, I noticed multiple uses of it. Is it ever advantageous to use 'goto' in a language that supports loops and functions? If so, why?

A: 

In Perl, use of a label to "goto" from a loop - using a "last" statement, which is similar to break.

This allows better control over nested loops.

The traditional goto label is supported too, but I'm not sure there are too many instances where this is the only way to achieve what you want - subroutines and loops should suffice for most cases.

Abhinav
Brad Gilbert
A: 

@jtyost2 : Why do you think that calling a function from another function using goto, would be simpler than exiting ?

Also, Couldn't we just call the function beta() in your example, get the results, and then return that out from the function ?

Abhinav
+2  A: 

The problem with 'goto' and the most important argument of the 'goto-less programming' movement is, that if you use it too frequently your code, although it might behave correctly, becomes unreadable, unmaintainable, unreviewable etc. In 99.99% of the cases 'goto' leads to spaghetti code. Personally, I cannot think of any good reason as to why I would use 'goto'.

cschol
Saying "I cannot think of any reason" in your argument is, formally, http://en.wikipedia.org/wiki/Argument_from_ignorance, although I prefer the terminology "proof by lack of imagination".
JUST MY correct OPINION
@JUST MY correct OPINION: It’s a logical fallacy only if it’s employed post-hoc. From a language designer’s point of view it may be a valid argument to weigh the cost of including a feature (`goto`). @cschol’s usage is similar: While maybe not designing a language right now, (s)he’s basically evaluating the designer’s effort.
Konrad Rudolph
+4  A: 

The rule with goto that we use is that goto is okay to for jumping forward to a single exit cleanup point in a function. In really complex functions we relax that rule to allow other jump forwards. In both cases we are avoiding deeply nested if statements that often occur with error code checking, which helps readability and maintance.

Doubt
+16  A: 

Basically, due to goto's defective nature (and I believe that this is uncontroversial), it is only used to compensate for missing features. So the use of goto may actually be acceptable, but only if the language doesn't offer a more structured variant to obtain the same goal. Take Doubt's example:

The rule with goto that we use is that goto is okay to for jumping forward to a single exit cleanup point in a function.

This is true – but only if the language doesn't allow structured exception handling with cleanup code (such as RAII or finally), which does the same job better (as it is specially built for doing it), or when there's a good reason not to employ structured exception handling (but you will never have this case except at a very low level).

In most other languages, the only acceptable use of goto is to exit nested loops. And even there it is almost always better to lift the outer loop into an own method and use return instead.

Other than that, goto is a sign that not enough thought has gone into the particular piece of code.

Konrad Rudolph
Just curious here, but what about the case of using gotos for clean up code. By clean-up, I mean, not only deallocation of memory, but also, say error logging. I was reading through a bunch of posts, and apparently, no one writes code that prints logs.. hmm?!
shiva
shiva: I'm not sure where you see a benefit of `goto` here. RAII and structured error handling are powerful mechanisms to facilitate logging. Admittedly, it's not done nearly enough because it *always* clutters the code.
Konrad Rudolph
*"Basically, due to goto's defective nature (and I believe that this is uncontroversial)"* -1 and I stopped reading there.
Lo'oris
@Lo'oris: That’s a pity. You could have learned something.
Konrad Rudolph
+33  A: 

There are a few reasons for using the "goto" statement that I'm aware of (some have spoken to this already):

Cleanly exiting a function

Often in a function, you may allocate resources and need to exit in multiple places. Programmers can simplify their code by putting the resource cleanup code at the end of the function all all "exit points" of the function would goto the cleanup label. This way, you don't have to write cleanup code at every "exit point" of the function.

Exiting nested loops

If you're in a nested loop and need to break out of all loops, a goto can make this much cleaner and simpler than break statements and if-checks.

Low-level performance improvements

This is only valid in perf-critical code, but goto statements execute very quickly and can give you a boost when moving through a function. This is a double-edged sword, however, because a compiler typically cannot optimize code that contains gotos.

Note that in all these examples, gotos are restricted to the scope of a single function.

Chris Gillum
The right way to exit nested loops is to refactor the inner loop into a separate method.
Jason
@Jason - Bah. That's a load of bull. Replacing `goto` with `return` is just silly. It's not "refactoring" anything, it's just "renaming" so that people who grew up in a `goto`-suppressed environment (i.e. all of us) feel better about using what morally amounts to a `goto`. I much prefer to see the loop _where I use it_ and see a little `goto`, which by itself is _just a tool_, than see someone having moved the loop somewhere unrelated just to avoid a `goto`.
Chris Lutz
There are sitations where gotos are important: for instance, an exception-less C++ environment. In the Silverlight source we have tens of thousands (or more) of goto statements for safe function exist through the use of macros - key media codecs and libraries often work through return values and never exceptions, and it's difficult to combine these error handling mechanisms in a single performant way.
Jeff Wilcox
It's worth noting that all `break`,`continue`,`return` are basically `goto`, just in nice packaging.
el.pescado
+7  A: 

In C# switch statement doest not allow fall-through. So goto is used to transfer control to a specific switch-case label or the default label.

For example:

switch(value)
{
  case 0:
    Console.Writeln("In case 0");
    goto case 1;
  case 1:
    Console.Writeln("In case 1");
    goto case 2;
  case 2:
    Console.Writeln("In case 2");
    goto default;
  default:
    Console.Writeln("In default");
    break;
}

Edit: There is one exception on "no fall-through" rule. Fall-through is allowed if a case statement has no code.

Jakub Šturc
Switch fall-through is supported in .NET 2.0 - http://msdn.microsoft.com/en-us/library/06tc147t(VS.80).aspx
Rob
Only if the case doesn't have a code body. If it does have code then you must use the goto keyword.
Matthew Whited
This answer is so funny - C# removed fall-through because many see it as harmful, and this example uses goto (also seen as harmful by many) to revive the original, supposedly harmful, behaviour, BUT the overall result is actually less harmful (because the code makes it clear that the fallthrough is intentional!).
thomasrutter
+1  A: 

If so, why?

C has no multi-level/labelled break, and not all control flows can be easily modelled with C's iteration and decision primitives. gotos go a long way towards redressing these flaws.

Sometimes it's clearer to use a flag variable of some kind to effect a kind of pseudo-multi-level break, but it's not always superior to the goto (at least a goto allows one to easily determine where control goes to, unlike a flag variable), and sometimes you simply don't want to pay the performance price of flags/other contortions to avoid the goto.

libavcodec is a performance-sensitive piece of code. Direct expression of the control flow is probably a priority, because it'll tend to run better.

DrPizza
+4  A: 

One of the reasons goto is bad, besides coding style is that you can use it to create overlapping, but non-nested loops:

loop1:
  a
loop2:
  b
  if(cond1) goto loop1
  c
  if(cond2) goto loop2

This would create the bizarre, but possibly legal flow-of-control structure where a sequence like (a, b, c, b, a, b, a, b, ...) is possible, which makes compiler hackers unhappy. Apparently there are a number of clever optimization tricks that rely on this type of structure not occuring. (I should check my copy of the dragon book...) The result of this might (using some compilers) be that other optimizations aren't done for code that contains gotos.

It might be useful if you know it just, "oh, by the way", happens to persuade the compiler to emit faster code. Personally, I'd prefer to try to explain to the compiler about what's probable and what's not before using a trick like goto, but arguably, I might also try goto before hacking assembler.

Anders Eurenius
Well...takes me back to the days of programming FORTRAN in a financial information company. In 2007.
Marcin
Any language structure can be abused in ways that render it unreadable or poorly-performing.
JUST MY correct OPINION
@JUST: The point is not about readability, or poor performance, but assumptions and guarantees about the flow-of-control graph. Any abuse of goto would be for *increased* performance (or readability).
Anders Eurenius
+26  A: 
Teifion
That better be Dennis Nedry (http://en.wikipedia.org/wiki/Dennis_Nedry)
Jeff Wilcox
-1 It's not funny.
Viktor Sehr
+6  A: 

#ifdef TONGUE_IN_CHEEK

Perl has a goto that allows you to implement poor-man's tail calls. :-P

sub factorial {
    my ($n, $acc) = (@_, 1);
    return $acc if $n < 1;
    @_ = ($n - 1, $acc * $n);
    goto &factorial;
}

#endif

Okay, so that has nothing to do with C's goto. More seriously, I agree with the other comments about using goto for cleanups, or for implementing Duff's device, or the like. It's all about using, not abusing.

(The same comment can apply to longjmp, exceptions, call/cc, and the like---they have legitimate uses, but can easily be abused. For example, throwing an exception purely to escape a deeply-nested control structure, under completely non-exceptional circumstances.)

Chris Jester-Young
I think this is the only reason to use goto in Perl.
Brad Gilbert
A: 

In C# switch statement doest not allow fall-through.

Actually...it does. You can do it either way. It says so on the page you linked.

Kevin
+1  A: 

Edsger Dijkstra, a computer scientist that had major contributions on the field, was also famous for criticizing the use of GoTo. There's a short article about his argument on Wikipedia.

bubbassauro
-1 for the http://en.wikipedia.org/wiki/Argument_from_authority
JUST MY correct OPINION
+1  A: 

In a Perl module, you occasionally want to create subroutines on the fly. The thing is, that once you have created the subroutine, how do you get to it. You could just call it, but then if the subroutine uses caller() it won't be as helpful as it could be. That is where the goto function can be helpful.

Here is a quick example of where it can be helpful:

sub AUTOLOAD{
  my($self) = @_;
  my $name = $AUTOLOAD;
  $name =~ s/.*:://;

  *{$name} = my($sub) = sub{
    # the body of the code
  }

  goto $sub;

  # nothing after the goto will ever be executed.
}


You can also use this form of goto to provide a rudimentary form of tail-call optimization.

sub factorial($){
  my($n,$tally) = (@_,1);

  return $tally if $n <= 1;

  $tally *= $n--;
  @_ = ($n,$tally);
  goto &factorial;
}
Brad Gilbert
+2  A: 

Just as well no one ever implemented the "COME FROM" statement....

Ken Ray
..except in INTERCAL! http://www.catb.org/~esr/intercal/
Bruce Alderman
+4  A: 

I've written more than a few lines of assembly language over the years. Ultimately, every high level language compiles down to gotos. Okay, call them "branches" or "jumps" or whatever else, but they're gotos. Can anyone write goto-less assembler?

Now sure, you can point out to a Fortran, C or BASIC programmer that to run riot with gotos is a recipe for spaghetti bolognaise. The answer however is not to avoid them, but to use them carefully.

A knife can be used to prepare food, free someone, or kill someone. Do we do without knives through fear of the latter? Similarly the goto: used carelessly it hinders, used carefully it helps.

boost
Perhaps you want to read why I believe this is fundamentally wrong at http://stackoverflow.com/questions/46586/goto-still-considered-harmful#47476
Konrad Rudolph
+1 Totally agree
Lo'oris
Anybody who advances the "it all compiles down to JMP anyway!" argument basically doesn't understand the point behind programming in a higher level language.
Cirno de Bergerac
Your point being?
boost
+5  A: 

Obeying best practices blindly is not a best practice. The idea of avoiding goto statements as one's primary form of flow control is to avoid producing unreadable spaghetti code. If used sparingly in the right places, they can sometimes be the simplest, clearest way of expressing an idea. Walter Bright, the creator of the Zortech C++ compiler and the D programming language, uses them frequently, but judiciously. Even with the goto statements, his code is still perfectly readable.

Bottom line: Avoiding goto for the sake of avoiding goto is pointless. What you really want to avoid is producing unreadable code. If your goto-laden code is readable, then there's nothing wrong with it.

dsimcha
+1 This is very reasonable and well written, who downvoted is yet another goto-hating-zombie.
Lo'oris
+2  A: 

I find it funny that some people will go as far as to give a list of cases where goto is acceptable, saying that all other uses are unacceptable. Do you really think that you know every case where goto is the best choice for expressing an algorithm?

To illustrate, I'll give you an example that no one here has shown yet:

Today I was writing code for inserting an element in a hash table. The hash table is a cache of previous calculations which can be overwritten at will (affecting performance but not correctness).

Each bucket of the hash table has 4 slots, and I have a bunch of criteria to decide which element to overwrite when a bucket is full. Right now this means making up to three passes through a bucket, like this:

// Overwrite an element with same hash key if it exists
for (add_index=0; add_index &lt; ELEMENTS_PER_BUCKET; add_index++)
  if (slot_p[add_index].hash_key == hash_key)
    goto add;

// Otherwise, find first empty element
for (add_index=0; add_index &lt; ELEMENTS_PER_BUCKET; add_index++)
  if ((slot_p[add_index].type == TT_ELEMENT_EMPTY)
    goto add;

// Additional passes go here...

add:
// element is written to the hash table here

Now if I didn't use goto, what would this code look like?

Something like this:

// Overwrite an element with same hash key if it exists
for (add_index=0; add_index &lt; ELEMENTS_PER_BUCKET; add_index++)
  if (slot_p[add_index].hash_key == hash_key)
    break;

if (add_index >= ELEMENTS_PER_BUCKET) {
  // Otherwise, find first empty element
  for (add_index=0; add_index &lt; ELEMENTS_PER_BUCKET; add_index++)
    if ((slot_p[add_index].type == TT_ELEMENT_EMPTY)
      break;
  if (add_index >= ELEMENTS_PER_BUCKET)
   // Additional passes go here (nested further)...
}

// element is written to the hash table here

It would look worse and worse if more passes are added, while the version with goto keeps the same indentation level at all times and avoids the use of spurious if statements whose result is implied by the execution of the previous loop.

So there's another case where goto makes the code cleaner and easier to write and understand... I'm sure there are many more, so don't pretend to know all the cases where goto is useful, dissing any good ones that you couldn't think of.

Ricardo
+3  A: 

Well, there's one thing that's always worse than goto's; strange use of other programflow operators to avoid a goto:

Examples:

    // 1
    try{
      ...
      throw NoErrorException;
      ...
    } catch (const NoErrorException& noe){
      // This is the worst
    } 


    // 2
    do {
      ...break; 
      ...break;
    } while (false);


    // 3
    for(int i = 0;...) { 
      bool restartOuter = false;
      for (int j = 0;...) {
        if (...)
          restartOuter = true;
      if (restartOuter) {
        i = -1;
      }
    }

etc
etc
Viktor Sehr
+14  A: 

Everybody who is anti-goto cites, directly or indirectly, Edsger Dijkstra's GoTo Considered Harmful article to substantiate their position. Too bad Dijkstra's article has virtually nothing to do with the way goto statements are used these days and thus what the article says has little to no applicability to the modern programming scene. The goto-less meme verges now on a religion, right down to its scriptures dictated from on high, its high priests and the shunning (or worse) of perceived heretics.

Let's put Dijkstra's paper into context to shed a little light on the subject.

When Dijkstra wrote his paper the popular languages of the time were unstructured procedural ones like BASIC, FORTRAN (the earlier dialects) and various assembly languages. It was quite common for people using the higher-level languages to jump all over their code base in twisted, contorted threads of execution that gave rise to the term "spaghetti code". You can see this by hopping on over to the classic Trek game written by Mike Mayfield and trying to figure out how things work. Take a few moments to look that over.

THIS is "the unbridled use of the go to statement" that Dijkstra was railing against in his paper in 1968. THIS is the environment he lived in that led him to write that paper. The ability to jump anywhere you like in your code at any point you liked was what he was criticising and demanding be stopped. Comparing that to the anaemic powers of goto in C or other such more modern languages is simply risible.

I can already hear the raised chants of the cultists as they face the heretic. "But," they will chant, "you can make code very difficult to read with goto in C." Oh yeah? You can make code very difficult to read without goto as well. Like this one:

#define _ -F<00||--F-OO--;
int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO()
{
            _-_-_-_
       _-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
        _-_-_-_-_-_-_-_
            _-_-_-_
}

Not a goto in sight, so it must be easy to read, right? Or how about this one:

a[900];     b;c;d=1     ;e=1;f;     g;h;O;      main(k,
l)char*     *l;{g=      atoi(*      ++l);       for(k=
0;k*k<      g;b=k       ++>>1)      ;for(h=     0;h*h<=
g;++h);     --h;c=(     (h+=g>h     *(h+1))     -1)>>1;
while(d     <=g){       ++O;for     (f=0;f<     O&&d<=g
;++f)a[     b<<5|c]     =d++,b+=    e;for(      f=0;f<O
&&d<=g;     ++f)a[b     <<5|c]=     d++,c+=     e;e= -e
;}for(c     =0;c<h;     ++c){       for(b=0     ;b<k;++
b){if(b     <k/2)a[     b<<5|c]     ^=a[(k      -(b+1))
<<5|c]^=    a[b<<5      |c]^=a[     (k-(b+1     ))<<5|c]
;printf(    a[b<<5|c    ]?"%-4d"    :"    "     ,a[b<<5
|c]);}      putchar(    '\n');}}    /*Mike      Laman*/

No goto there either. It must therefore be readable.

What's my point with these examples? It's not language features that make unreadable, unmaintainable code. It's not syntax that does it. It's bad programmers that cause this. And bad programmers, as you can see in that above item, can make any language feature unreadable and unusable. Like the for loops up there. (You can see them, right?)

Now to be fair, some language constructs are easier to abuse than others. If you're a C programmer, however, I'd peer far more closely at about 50% of the uses of #define long before I'd go on a crusade against goto!

So, for those who've bothered to read this far, there are several key points to note.

  1. Dijstra's paper on goto statements was written for a programming environment where goto was a lot more potentially damaging than it is in most modern languages that aren't an assembler.
  2. Automatically throwing away all uses of goto because of this is about as rational as saying "I tried to have fun once but didn't like it so now I'm against it".
  3. There are legitimate uses of the modern (anaemic) goto statements in code that cannot be adequately replaced by other constructs.
  4. There are, of course, illegitimate uses of the same statements.
  5. There are, too, illegitimate uses of the modern control statements like the godo abortion we can find right here in this very thread. These are often worse than judicious use of goto.

Keep in mind while you're voting me down with one -1 after another that I have used goto in my own (non-assembler) code precisely 3 times in the past 15-20 years.

I await the flood of outraged shrieks and -1 votes with bated breath.

JUST MY correct OPINION
So here is the first wave: +1 for a clear statement while keeping free of dogma.
Boldewyn
And, of course, we have the typical -1 from an anonymous coward unwilling to state why this answer is, and I quote, "not useful".Care to give a courtesy flush after dropping the turd, coward?
JUST MY correct OPINION
"Not a goto in sight, so it must be easy to read, right?" <-- this is a pretty blatant straw man from denying the antecedent right here, fyi.
Cirno de Bergerac
"You can make code very difficult to read without goto as well." <-- so two wrongs make a right? at best, you can extrapolate that goto is merely *no worse* that an IOCCC entry.
Cirno de Bergerac
"Care to give a courtesy flush after dropping the turd, coward?/I can already hear the raised chants of the cultists as they face the heretic/I await the flood of outraged shrieks and -1 votes with bated breath." <-- This isn't any kind of logical fallacy at all, really, but it does make you sound like an 8 year old.
Cirno de Bergerac
"I'd peer far more closely at about 50% of the uses of #define long before I'd go on a crusade against goto!" <-- In fact, you can do both!
Cirno de Bergerac
… @sgm has already said it: that’s one huge pile of logical fallacies. I just want to comment on one thing: You said you have used `goto` 3 times in the past x years – tell me, how does this compare to *any* other “general-purpose” language feature (I explicitly exclude specialized, yet sometimes necessary language features such as `volatile` which some people just don’t need)? Isn’t it odd that a *general-purpose* language feature gets used so little in good code? For me, that’s a strong indication that `goto` doesn’t bring much to the table. I.e., that it is defective. Go figure.
Konrad Rudolph
@Konrad Rudolph: Let me rephrase your comment to show you the defect in your thinking. "I explicitly exclude exactly the kinds of language features that would undermine my so-called 'argument', so how do you justify this other language feature?"
JUST MY correct OPINION
@JUST MY correct OPINION: That is not at all like what I said. Just because two sentences are syntactically similar does not make them semantically equivalent. `volatile` is a non-redundant (i.e. cannot be replicated otherwise) special language feature. `goto` is general-purpose, and completely on-orthogonal with other language features.
Konrad Rudolph
+1 for putting Dijkstra's article into the historical context.
Treb
+1  A: 

I find the do{} while(false) usage utterly revolting. It is conceivable might convince me it is necessary in some odd case, but never that it is clean sensible code.

If you must do some such loop, why not make the dependence on the flag variable explicit?

for (stepfailed=0 ; ! stepfailed ; /empty/)

Sandy