Using a goto in this case...

Pages: 12
WARNING! POSSIBLE FLAME TOPIC AHEAD!

Do you think a goto would be justified in something like the following code:
1
2
3
4
5
6
7
8
for(int i = 0; i < i_size; ++i) {
    for(int j = 0; j < j_size; ++j) {
        if(j >= 10 && i < 2) goto escape;
        //do some stuff
    }
}
escape:
//... 


As opposed to:
1
2
3
4
5
6
7
8
int i = 0, j = 0;
for(i = 0; i < i_size; ++i) {
    for(j = 0; j < j_size; ++j) {
        if(j >= 10 && i < 2) break;
        //do stuff
    }
    if(j >= 10 && i < 2) break;
}


Do you think it is worth the goto to save some temporary variable names? What about if there were more loops with individual exit circumstances?

Personally, I think that a goto is probably not needed, but I wouldn't complain if someone used one.
closed account (z05DSL3A)
As long as goto is used properly, there is nothing wrong with it.
This actually is a rather heated discussion topic.

There are those that prefer "flaggy" code -- adding all kinds of conditions and stuff into code to tell it when to quit.

There are those that just use the best construct available -- like a goto (or an exception or other jumping construct).

The pros and cons have already been hashed and rehashed at length... so I'll refrain from more here.

Personally, I agree with Grey Wolf.
Last edited on
GOTO IS EVIL GOTO IS SYSTEM()! -blah blah blah... It's nothing wrong to use goto unless you do jump from line 7286 to line 1941.
What about making the two for() loops the entire body of a function and replace the goto with a return?
A function call/return is a glorified goto with additional overhead. ;-]
Last edited on
closed account (z05DSL3A)
For anyone interested:

Computer scientists are zealous in their beliefs, and when the discussion turns to gotos, they get out their jousting poles, armor, and maces, mount their horses, and charge through the gates of Camelot to the holy wars.

No one quarrels with using gotos to emulate structured constructs in languages that don't support structured control constructs directly. The debate is about languages that support structured constructs, in which gotos are theoretically not needed. Here's a summary of the points on each side.


read more here: http://www.stevemcconnell.com/ccgoto.htm
I believe I have with me one of the best possible examples of "there are cases when goto is the only way to go":
1
2
3
4
5
6
7
8
9
10
11
//...
label_000:
//Somewhat complex stuff here.
if (/*...*/){
    if (/*...*/){
        //...
        goto label_000;
    }
    //...
}
//... 

I'm fairly sure there is no way to write this without using goto and without duplicating code. To preemptively answer jsmith, extra function calls in this case are not acceptable.
Last edited on
lol

@Duoas:
I suggested the return because functions should do one thing and do it well. Not knowing the specifics of the scenario, it might make sense to break the logic into smaller components, or the loops might be part of a larger, but still atomic, piece of logic that simply doesn't make sense to break apart. I don't know -- the original example was purely academic.

Though thinking about it more, I find myself using std::for_each in combination with lambda expressions for simple, non-nested loops and std::for_each in combination with lambda binds or boost binds (resulting in a call to a separate function which would then contain the second for loop) for nested ones.

@helios:
Well, what can I say? If the reason function calls are not acceptable is because the code is performance critical, fair enough, although then you should have stated that as part of the example. Otherwise I can't think of a reasonable reason why function calls would not be acceptable.

I must reiterate... in 12+ years of professional programming, I have never once used a goto, nor even encountered a scenario where I had to sacrifice something to avoid it. Not that I'm completely against using them; I just have never found a case where they were necessary. [To be fair, I've only worked on soft realtime systems where performance is (very) important but not critical.]




I use this construct all the time:

1
2
3
4
5
6
7
8
9
10
11
bool repeat = true;
while(repeat)
{
  // complex stuff here
  if( /**/ ){
    if( /**/ ){
      continue;
    }
  }
  repeat = false;
} // while 
Hmm... Wasn't that called "the poor-man's try-catch"?

jsmith: Well, not necessarily. Since the discussion on goto is merely from the point of view of structured programming and not any language in particular, I could say that that snippet was written in a dialect of C that doesn't support functions other than main().
Wasn't that called "the poor-man's try-catch"?


I thought that was goto?
continue and break are gotos in disguise. Also, I just realized while typing this that you mean break, not continue.
Oops. Never mind. I was thinking this:
1
2
3
4
5
6
7
8
9
10
11
12
bool error=0;
do{
    //...
    if(/*...*/){
        error=1;
        break;
    }
    //...
}while (0);
if (error){
    //something error happens
}
Last edited on
@helios:

But even assembler supports the notion of functions. Even shell scripts support functions. Name for me one programming language that does not support functions and I'll give some weight to your response. [Note: even Basic's GOSUB implies that Basic supports functions...]
It's a hypothetical language.
Ok, in that case, I rest my case. However, that aside (I'm really not about starting flame wars) I think that all flow control structures--if, for, while, do-while, switch-case, break, continue, and even functions--are essentially glorified gotos. After all, they all do the same thing -- they create a non-linear execution path through the code by instantaneously jumping from one place either forward or backward. The real difference between them is that goto can be used to go anywhere, whereas the other flow control structures have a clear entry point and exit point. This is why it is easy to reason about while() loops and for() loops and not-so-easy to reason about misused gotos. And this is why nobody argues about the use of control structures. But not all gotos are bad, I agree. For example, what is the difference between

1
2
3
for( i = 0; i < 10; ++i )
    if( i == 5 )
        break;


and

1
2
3
4
5
6
for( i = 0; i < 10; ++i )
    if( i == 5 )
         goto done;

// No code being skipped over...
done:


[Ok, yes, stupid examples. Just to illustrate my point.]

As long as it is clear that the "done" label is not used anywhere else (which takes a slight amount of effort), from a complexity standpoint, they are identical. Heck, the generated code might even be identical.

Purists of course will say to use break instead of goto, but in reality, in the above example there is no difference.

When you start using gotos to skip over arbitrary amounts of code

1
2
3
4
5
6
7
8
9
10
11
12
int j = 0;
for( i = 0; i < 10; ++i )
    if( i == rand() % 10 )
         goto done;

// Lots of code here:
// ...
j = 5;

done:
// More code here
// Is j == 0 or 5 here? 


that's when it gets very hard to reason about the code. For example, what is the value of j post the "done" label above? Well, in this example you can't know, but even when you can know, it might require a few braincells to determine it. Fewer braincells required to understand code is always better. In my opinion, this example is a bad example of goto usage.

But C++ has issues with goto that make things even worse:

1
2
3
4
5
6
7
8
9
10
11
for( i = 0; i < 10; ++i )
    if( i == rand() % 10 )
         goto done;

// Lots of code here:
// ...
string hello_world = "Hello World!";

done:
// More code here
cout << hello_world;


The problem here is that hello_world's constructor is never run if the goto is executed, which means that the cout crashes. But if the goto is not executed, the code works fine. gotos in C++ allow you to bypass initialization of variables, and that is an even more compelling reason than understandability to avoid gotos in C++.

[For those who claim that a legitimate reason to bypass initialization is because construction of the object is either very expensive or causes unwanted side effects, I say that is what boost::optional is for.]


I think that goto sucks in this case (exaggeration ahead):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// ...

here:

if(/* ... */)
goto everywhere;
else
goto end;

// ...

there:

if(/* ... */)
goto here;

// ...

everywhere:

if(/* ... */)
goto there;

end:
return 0;


But in that case, jsmith, I'm not sure...that's also where goto is, er, dumb. :D
Last edited on
@ Null
from line 7286 to line 1941.

That is some immense code... I would be trying to find a way to break that down a little before I even thought of using gotos, like create some header files... function declarations in one, classes in another, constants in another (library).
I dramatized this too much :-).
@greywolf, As long as goto is used properly, there is nothing wrong with it.

Define properly. There isn't a fine line between proper and improper use of goto in my mind.

1
2
3
4
5
6
7
for(int i = 0; i < i_size; ++i) {
    for(int j = 0; j < j_size; ++j) {
        if(j >= 10 && i < 2) goto escape;
        //do some stuff
    }
}
escape:


No offense but these kinds of examples bug me just a little. How much code is "do some stuff"? The example doesn't make any sense to me. I have been writing C++ code for over 8 years and have never once needed to write a goto statement. I'm not the type of person who likes coding standards that are too restrictive. I've worked with many that prevented me from using the goto tool. However, it has never bothered me because I have never needed it. Many people here are saying that if..else, switch, continue, break, function calls, and so forth are all glorified gotos but I disagree. Goto is more of a hack. There is very little in terms of syntactical restrictions that prevent you from using gotos in ways that are atrocious, illogical, and unnecessary. If you want to make a case for using goto, please provide some kind of a real example that shows where it is used in a way that it is better then other options.

Try.. catch blocks, switch, if..esle, do..while, all have logical syntactical restrictions that result in clearer, less error prone code. Even back when I wrote assembly code for a living I was restricted by coding standards from using goto like mechanisms as described in some of the previously shown examples.
Last edited on
Pages: 12