goto (programming)

Recently there was a thread about the use of goto, and the general consensus was that goto was worthless and should never be used.

Recently I have been doing a lot of programming in C, and I think I have found three very legitimate uses for goto.

The first is exactly the same as the break keyword, but for nested loops:


for(loop)
  {
    for(anotherloop)
      {
	if(condition)
	  goto endloop;
      }
  }
endloop:

If you accept that break is legitimate, I don’t see why this use of goto would not be legitimate. When I was in computer science class and my instructor regarded the use of goto as a mortal sin, I would write such loops this way:


int endloop = 0;
for(loop)
  {
    for(anotherloop)
      {
        . . .
      	if(condition)
	  {
	    endloop = 1;
	    break;
	  }
	. . .
      }
    if(endloop)
      break;
    . . .
  }

which is just horribly complicated and inelegant.

Another use: suppose, in a complicated function, there are several circumstances under which things could go wrong, in which case you want to clean things up and return an error code. You could use a separate function, or in C++ use a try-catch, but to me it’s simpler to use a goto:


int bigfunction()
{
  dostuff;
  if(condition)
    goto error;
  dostuff;
  if(condition)
    goto error;
  dostuff;
  . . .
  return SUCCESS;

 error:
  cleanupstuff;
  return ERROR;
}

A matter of taste, I suppose, but I find the above code very palatable.

Finally, suppose you have a for loop and under certain circumstances you want to restart the loop:


startloop:
for(loop)
  {
    . . .
    if(condition)
      goto startloop;
    . . .
  }

Now I know in some loops you could do this:


int i;
for(i = 0 ; i < 10 ; i++)
  {
    . . .
    if(condition)
      {
        i = -1;
	continue;
      }
    . . .
  }

But what if you were stepping through a linked list?


llist_t *tmp_node;
for(tmp_node = llist_head ; tmp_node != NULL ; tmp_node = tmp_node->next)
  {
    . . .
    if(condition)
      ???
    . . .
  }

I believe there is no way to do this without a goto.

Admittedly, this last circumstance is rare, and not one that ended up being in my program. But I contend that it could happen, and a goto would then be very useful.

Debate.

The first two are pretty much the default programming style for Linux. And looking over that code, I’ve never been boggled in the least. But the coders doing Linux are generally not n00b haxx0rz–since, pretty much, whether goto ends up being good or not comes down to whether or not the coder was a good coder, not the evil-quotient of goto.

The third one… do {} while (!done); ? I’ve never seen a goto used like that and it certainly doesn’t look encouraging in your presentation–it’s a manual do {} while and just adds extra work to make it go.

You’re right. I never thought to use a do-while because, frankly, I almost never use them, and haven’t in a long time. I am a little puzzled, though, when you say that my way takes more work. Your method, as far as I can tell, would require at least one extra test.

I first started to learn programming in the early 70’s, before structured coding really came into vogue. Trying to follow another programmer’s code was literally like trying to trace a stand of spaghetti. Everyone’s code was liberally sprinkled with GOTO statements and it was a big mess.

The concept of structured code was to make things more readable and easily followed by others. One of the “prime directives” of the structured coding movement (if you can call it that) was to make it possible to perform any given algorithm without using a GOTO statement. Hence the directive that GOTO is evil and is to be avoided at all costs.

In many cases the structured equivalent would compile to the exact same machine code as if a GOTO were used, but it would be cleaner and simpler to read.

Even in your last case, there are ways to avoid using a GOTO. For example, on testing for [condition] you could set a flag to be tested downstream somewhere, and then use an IF…THEN…ELSE construction based on the results of the flag.

The object of the structured paradigm is not to find valid reasons to use a GOTO, but to find ways around it.

I’ve done it both ways, and I can readily tell you which I prefer.

I, too, have been to GOTO land. That is, I’ve had to work on code where the original author used GOTO. And in my nearly twenty years in the business, I have never, ever, ever, ever found a GOTO that was justifiable. For those of you who think you have an elegant situation that just cries out for GOTO, I beg you to reconsider, for the sake of the next guy that has to come along and figure out your oh-so-clever solution.

I first learned to program on a TI calculator, and I ended up writing some very elaborate programs on it before I learned a real language. So I am familiar with the horrors of writing and maintaining code that depends on gotos.

My only suggestion is that for some problems, goto is still the best and simplest solution. My latest project is up to 1,100 lines and uses goto only twice. I don’t think that’s spaghetti code.

How would you rewrite my first example in a way that is simpler for someone else to understand?

Well, let’s see; testing the linked list one.



retry:
for (current = head; current != head; current = current.next) { /* one test here, current != head */
        list_needs_to_be_reprocessed = do_funky_stuff();

        if (list_needs_to_be_reprocessed) goto retry; /* another test */
}




current = head;

do {
        ist_needs_to_be_reprocessed = do_funky_stuff();

        current = next;
} while (list_needs_to_be_reprocessed); /* one test here */


patch #1

  •    ist_needs_to_be_reprocessed = do_funky_stuff();
    
  •    current = next;
    
  •    list_needs_to_be_reprocessed = do_funky_stuff();
    
  •    current = current.next;

Alright, let’s just ignore that second bit of code (it’s 6:45am here.) That’s what I was thinking of when I wrote that, but it’s busted code. So yeah, you need three tests to do the do-while.



do {
        for (current = head; current != head; current = current.next) { /* one test */
                list_needs_to_be_reprocessed = do_funky_stuff();

                if (list_needs_to_be_reprocessed) break; /* two tests */
        }
} while (list_needs_to_be_reprocessed); /* three tests */


I must say though that I’ve never needed to cease processing on a structure midway through to go back and restart it. If you’ve come to that, I think that minimizing the number of conditions you are testing is the least of your concerns.

Indeed, I only ever wrote that code because my more efficient algorithm wasn’t working, and I was basically brute-forcing it as an alternative. When I discovered the problem, the need for the goto went away. But I felt that there may be some circumstances where restarting the loop as such is the only option.

The proper indentation of the do-while does a lot more for me to make the code work correctly than shaving one nanosecond off the loop.

But as I said earlier, goto is mostly bad if the programmer isn’t good at thinking in terms of maintenance. If he is good at thinking ahead to four years down the line and feels that a goto makes perfect sense, then all the power to him. The question is: Are you that programmer? Well, probably best to wait four years and go back to your code before making that decision.

To handle the first case, the Java language introduced the “labelled break”, which was essentially a goto with a different name. I’d say that goto in the first case is appropriate.

I’ve only ever considered using goto once. I found that I could beat the optimizer and shave an instruction off of a function by using a goto to the end of the function rather than returning. Normally I wouldn’t have cared, but in this case I had to fit the entire program in 64 KB, and having it go above 12 KB had enormous performance implications. Now, I was doing a lot of assembly coding at the time, so I wasn’t exactly in a structured programming frame of mind. I can’t remember if I ended up using the goto or not, but I do remember being annoyed that the optimizer couldn’t perform such a simple optimization for me.

I see nothing wrong with your first example and would not chastise my developers for doing it. Indeed, as you pointed out, the alternative is to have more flags than the united nations. I have long said that a properly used goto is not as horrible as it has been made out to be. However, I am in the minority usually.

In good code, the physical structure of the code on the page corresponds very highly with the logical structure of what it’s doing. For 99% of us, that correspondence is significantly more valuable than the time saved by not doing an extra comparison on every iteration of a loop, or the space saved by not throwing in error handling for breaking out of a loop.

goto violates the structure correspondence, and as a result is all but inexcusable. If you’re a student, or otherwise haven’t ever had to do maintenance programming, you may not appreciate that sentiment, but I’d have a really hard time believing that you have significant experience and don’t see the value of readable code.

To address your last example, consider this:


llist_t *tmp_node;
for(tmp_node = llist_head ; tmp_node != NULL ; tmp_node = tmp_node->next)
  {
    . . .
    if(condition)
      tmp_node = llist_head;
    . . .
  }

One other point regarding break vs. goto is that with C++, where you can declare your loop variables within the loop, break will immediately descope the variables, where goto will not. To make it plainer, goto will introduce memory leaks.

Ewww, did not know that. (Though it makes sense.)

Leaking a stack-based variable is an accomplishment.

The thing I like least about goto is that it requires a labelled statement as its target. As soon as you have a statement label in your program, it could potentially be targetted by any number of gotos anywhere in the code, which makes it a bitch to maintain, especially if it is being maintained by somebody other than the original author.

ultrafilter, your suggestion would not work. Notice the ellipses: there is code being executed before the test. With your method that code would not be executed on the head of the list.

With the loop as you’ve written it, that’s not correct.