Page 1 of 3

goto instruction

Posted: Wed Mar 09, 2011 4:30 pm
by sancho1980
In our company I kind of had an argument with our senior programmer about the use of the goto instruction.
I know it's considered to be harmful, but we have already a convention in our company to use gotos to jump to the end of a function for cleanup purposes. While talking about that with him, I said I could also think of other situations where gotos can be helpful and he asked which and I said I oftentimes like to use them to jump over code, so instead of writing something like:

Code: Select all

int func()
{
    step1;
    step2;
    step3;
    if (x) {
        step4;
        step5;
        step6;
        step7;
    }
    step8;
    step9;
    step10;
return 0;
}
I prefer to write

Code: Select all

int func()
{
    step1;
    step2;
    step3;
    if (!x) {
        goto over_steps4567;
    }
    step4;
    step5;
    step6;
    step7;
over_steps4567:
    step8;
    step9;
    step10;
return 0;
}
What I like about this is above all that it avoids indentation, and I don't think it's bad because it's only a forward goto and now jumping around blindly from a to z to b.

He told me he didn't agree at all and asked me whether I thought I was smarter than all these programmers out there who say goto is bad and said I wasn't allowed to write such kind of code any more. I usually don't bother too much when he criticises that I place too many or too few blank lines between my functions or whatever detail of my coding style he doesn't like, but this really brought me upset. What do you guys think; is this already "bad use" of goto?

Re: goto instruction

Posted: Wed Mar 09, 2011 4:34 pm
by a5498828
c is not an asm, you have functions. first code is much better.

Re: goto instruction

Posted: Wed Mar 09, 2011 4:41 pm
by gerryg400
I'm afraid I agree with him. It would not pass code review here. Not, in the first instance because you used goto, but because you avoided indentation. Indentation in this case should be used to show at a cursory glance that the middle block of code is not part of the 'always-executed' code path. This would be more likely to be passed

Code: Select all

int func()
{
    step1;
    step2;
    step3;
    if (!x) {
        goto over_steps4567;
    }
    else {
        step4;
        step5;
        step6;
        step7;
    }
over_steps4567:
    step8;
    step9;
    step10;
return 0;
}
At this point the goto is unnecessary, as it usually is in properly structured c, and eventually the code is written as he originally suggested.

Re: goto instruction

Posted: Wed Mar 09, 2011 4:47 pm
by neon
Hello,

If a function constitutes of that many steps that require the use of goto to improve readability I would look into ways to simplify the function by breaking it apart.

Re: goto instruction

Posted: Wed Mar 09, 2011 5:16 pm
by linguofreak
sancho1980 wrote:What I like about this is above all that it avoids indentation, and I don't think it's bad because it's only a forward goto and now jumping around blindly from a to z to b.
Indentation is good for readability. Furthermore, if you absolutely want to avoid indentation, you can do this:

Code: Select all

int func()
{
    step1;
    step2;
    step3;
    if (x) {
    step4;
    step5;
    step6;
    step7;
    }
    step8;
    step9;
    step10;
return 0;
}
or even

Code: Select all

int func(){step1;step2;step3;if (x){step4;step5;step6;step7;}step8;step9;step10;return 0;}
Either bit of code is just as valid as far as the compiler is concerned. I wouldn't expect your boss to be very happy with it though, as most people find either one much less readable. The way he wants you to write it makes it easier for other people to work with.
What do you guys think; is this already "bad use" of goto?
Yes.

Re: goto instruction

Posted: Wed Mar 09, 2011 6:08 pm
by bewing
I disagree with just about everyone here. Using 'goto' is not a question of intelligence, or badness. It is merely a religious/philosophical question. A bit more than a question of mere style, but still.

The CPU uses goto/JMP for just about every line of code you write. Avoiding 'goto' is an attempt to avoid what the CPU does best, and that is one of the reasons why everyone's code today runs so slowly, and is such immense fatware.

Creating functions as a series of 'steps' can be much more readable than trying to create code blocks with indentation. To blindly do one or the other is foolish.

Unfortunately, the programming world is just as full of religious zealots as the Southern USA.

Re: goto instruction

Posted: Wed Mar 09, 2011 7:17 pm
by linguofreak
bewing wrote:I disagree with just about everyone here. Using 'goto' is not a question of intelligence, or badness. It is merely a religious/philosophical question. A bit more than a question of mere style, but still.

The CPU uses goto/JMP for just about every line of code you write. Avoiding 'goto' is an attempt to avoid what the CPU does best, and that is one of the reasons why everyone's code today runs so slowly, and is such immense fatware.
Goto *is* often avoided a bit too religiously, but in the OP's case I'm pretty sure it will run slower, since, when it's finally turned into machine code, you'll have 2 JMP's where you only need one. The if statement already has an implicit JMP if x is false, and then the goto is a JMP, and so you end up doing a JMP/Goto regardless of the value of x, whereas you only *need* a JMP if x is false, and if x is true you can just let execution continue linearly.
Creating functions as a series of 'steps' can be much more readable than trying to create code blocks with indentation. To blindly do one or the other is foolish.
The "steps" issue, the goto issue, and the indentation issue here are three separate issues. For the purposes of the OP's question, whether we do:

Code: Select all

int func()
{
    step1;
    step2;
    step3;
    if (!x) {
        goto over_steps4567;
    }
    step4;
    step5;
    step6;
    step7;
over_steps4567:
    step8;
    step9;
    step10;
return 0;
}
or

Code: Select all

int func()
{
    step1;
    if (!x) {
        goto over_step2;
    }
    step2;
over_steps2:
    step3;
return 0;
}
is moot. As is whether we do:

Code: Select all

int func()
{
    step1;
    if (!x) {
        goto over_step2;
    }
    step2;
over_steps2:
    step3;
return 0;
}
or

Code: Select all

int func(){ step1; if (!x) { goto over_step2; } step2; over_steps2: step3; return 0;}
There are reasons why one would (or would not) want to do each one, but it's orthogonal to the goto issue.

Re: goto instruction

Posted: Wed Mar 09, 2011 7:20 pm
by gerryg400
bewing wrote:I disagree with just about everyone here. Using 'goto' is not a question of intelligence, or badness. It is merely a religious/philosophical question. A bit more than a question of mere style, but still.

The CPU uses goto/JMP for just about every line of code you write. Avoiding 'goto' is an attempt to avoid what the CPU does best, and that is one of the reasons why everyone's code today runs so slowly, and is such immense fatware.

Creating functions as a series of 'steps' can be much more readable than trying to create code blocks with indentation. To blindly do one or the other is foolish.

Unfortunately, the programming world is just as full of religious zealots as the Southern USA.
Bewing, nobody said that using goto was related to intelligence or badness. In fact most of the comments centred around the need for indenting the code. And we didn't say that indenting or not indenting was always bad. Most of the comments were about this particular example. I don't believe that you disagree with just about everyone here.

Re: goto instruction

Posted: Thu Mar 10, 2011 12:35 am
by Solar
bewing wrote:The CPU uses goto/JMP for just about every line of code you write. Avoiding 'goto' is an attempt to avoid what the CPU does best...
I counter that with another quote:
Martin Fowler wrote:Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
That's why 'goto' is shunned. Anyone who can draw a Nassy-Shneiderman diagram knows what I mean.
...and that is one of the reasons why everyone's code today runs so slowly, and is such immense fatware.
You're kidding, right? I mean, do you really believe what you just said? That software today runs "so slow" because people no longer use 'goto'?

Edit: Or that the two examples given by sancho1980 would actually result in any difference in the compiled code?

#-o

Re: goto instruction

Posted: Thu Mar 10, 2011 3:48 am
by Fanael
bewing wrote:Avoiding 'goto' is an attempt to avoid what the CPU does best
What CPU does best are simple arithmetic (addition, subtraction), bitwise operations, and the like. CPUs don't like branching, actually. Especially the ones mispredicted by the branch predictor.

Re: goto instruction

Posted: Thu Mar 10, 2011 3:53 am
by turdus
Actually goto can make code clearer, but your example is bad.
It's nested structures where goto come handy in structured languages, like

Code: Select all

int flag1=true;
while(flag1&&expr1){
   ....
   while(expr2){
      ....
      //and here you want to break both loops
      if(expr3) { flag1=false; break; }
   }
}
That's messy. It's much clearer to write

Code: Select all

while(expr1){
   ....
   while(expr2){
     ....
     if(expr3) goto break_loops;
   }
}
break_loops:
Only use goto if it does not lead to spaghetti-code, and you'll be fine.

Re: goto instruction

Posted: Thu Mar 10, 2011 4:16 am
by Solar
turdus wrote:Actually goto can make code clearer...
...but not as much as properly designed code.
...but your example is bad. [...] Only use goto if it does not lead to spaghetti-code, and you'll be fine.
Any goto by definition leads to spaghetti code. It might jump to the right place, and it might take into account any variable assignments it jumped over, but you simply never know unless there is additional documentation. Unfortunately, the attitudes "goto is not evil" and "code does not need comments" too often go hand in hand.

Code: Select all

inline void foo()
{
    while ( expr1 )
    {
        // ...
        while ( expr2 )
        {
            // ...
            if ( expr3 ) return;
        }
    }
}

Re: goto instruction

Posted: Thu Mar 10, 2011 4:42 am
by turdus
Solar wrote:
turdus wrote:Actually goto can make code clearer...
...but not as much as properly designed code.
Agree. In nearly 20 years of development I found only a few situations where goto was better (or even the only solution). Less than 1%.
Solar wrote: Any goto by definition leads to spaghetti code. It might jump to the right place, and it might take into account any variable assignments it jumped over, but you simply never know unless there is additional documentation. Unfortunately, the attitudes "goto is not evil" and "code does not need comments" too often go hand in hand.
Disagree on that. Imagine a code where no goto crosses, it wouldn't be a unfollowable spaghetti-code. But it's quite rare, so you are right that comment is a must.

Your code (which is good and readable solution) has a disadvantage that you introduced plus stack handling and two more branches. This could be a problem if performance matters (and frankly speaking in a kernel almost all the time it matters). So your code is good, but not universal, I do not recommend to use it without examining the concrete situation.

Re: goto instruction

Posted: Thu Mar 10, 2011 4:44 am
by Combuster
Ever heard of compiler optimalisations (read: inline functions)?

Re: goto instruction

Posted: Thu Mar 10, 2011 4:53 am
by Solar
turdus wrote:Your code (which is good and readable solution) has a disadvantage that you introduced plus stack handling...
inline...
...and two more branches.
Nope, I copied your example exactly, including the check on expr1 and expr2.