Using goto is OK?

Pages: 12
the biggest problem of goto is not even the actual use. With a lot of thinking you may make it right.

the most horrifying experience is to modify/expand such a code with all the jumping forth and back not caring for scope and everything.

a code with a goto is usually dead code.
the most horrifying experience is to modify/expand such a code with all the jumping forth and back not caring for scope and everything.

a code with a goto is usually dead code.

Yes, exactly. It maybe something that bedroom programmers don't have to worry about, but for those of us who actually do this for a living, goto is a terrible thing to use. A huge part of working as a professional software developer is maintaining existing code, and trying to fix/modify something with goto statements in is orders of magnitude more time-consuming and error-prone.

If you're even vaguely thinking that you might want to do this for a living one day, get out of the habit of using goto now.
goto seems to be referred to like some black magic. As far as I can tell the situation is simple: use goto as much as you want, but keep in mind that it makes code harder to read. Control structures should be used if you want well-written readable code. But if you don't care about readable code there's no point telling you it's black magic because you're either already a lost cause or will very quickly figure out for yourself how important readable code is.

Half of the point of modern code is to make it easy to write programs, the other half is to make it easy to read them. If you regularly use goto you're probably wrecking that other aspect, but then again we're all consenting adults: you're free to use it if you really want to.

If you want to work in software development you're also doing yourself a favour writing code without goto because chances are wherever you work they'll ban using goto unless there's a really good reason for it: AKA not in usual code.

EDIT: Fixed code tags.
Last edited on
> with all the jumping forth and back not caring for scope and everything.
> a code with a goto is usually dead code.

Use of scopes is completely orthogonal to the use of goto. A programmer who would use a scope if and only if a syntactic rule forces one to do so is a poor programmer - no matter that the eschewal of goto is zealously adhered to with religious fervour.



> "goto" is such a dangerous construct, and can have such a negative impact on maintainability
> goto is a terrible thing to use.

Absolute balderdash.

If goto is really a terrible thing to use, no matter how it is used, be certain that it would have become a deprecated feature of the language.

This:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
do // read_next_item:
{
    // ...

    if( ... ) continue ; // goto read_next_item

    // ...

    if( ... ) break ; // goto no_more_items

    // ...

} while( ... ) ; // if( ... ) goto read_next_item

// no_more_items: 
do_something_with_the_items() ;


is not any more readable or maintainable than this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
read_next_item: // do
{
    // ...

    if( ... ) goto read_next_item ; // continue

    // ...

    if( ... ) goto no_more_items ; // break

    // ...

    if( ... ) goto read_next_item ; // while( ... )
}

no_more_items: 
    do_something_with_the_items() ;


Have nested loops, with a need to break out of some of them, and the version going through grotesque contortions to avoid that one goto somehow, anyhow, would be likely to be less readable and less maintainable.



Grey Wolf wrote:
goto is not bad it is just misused. Learn what it does and how to use it. There is often a better way than using goto but sometimes you will find that it is a simple way to achieve something.


Grey Wolf: +1

People who not know how to use a particular programming construct correctly would be well advised not use it; not till they have educated themselves. That is as true of goto as it is for (say) virtual inheritance.



> the situation is simple: use goto as much as you want,
> but keep in mind that it makes code harder to read.

Not necessarily. It can actually make the code easier to read.

From the post that TheIdeasMan had linked to:
Would this real-life (so I believe, it was on the internet, in a discussion of goto) C code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int parse()
{
    Token tok ;

    reading:
        tok = gettoken() ;
        if( tok == END ) return ACCEPT ;

    shifting:
        if( shift(tok) ) goto reading ;

    reducing:
        if( reduce(tok) ) goto shifting ;

    return ERROR ;
}


become simpler or more elegant if we banished the gotos?
closed account (z05DSL3A)
...but keep in mind that it makes code harder to read ... wherever you work they'll ban using goto unless there's a really good reason for it...


From "JOINT STRIKE FIGHTER AIR VEHICLE C++ CODING STANDARDS"
-----===##===-----
AV Rule 189
The goto statement shall not be used.

Rationale: Frequent use of the goto statement tends to lead to code that is both difficult to read and maintain.

Exception: A goto may be used to break out of multiple nested loops provided the alternative would obscure or otherwise significantly complicate the control logic.
-----===##===-----

So basically don't use goto because it is hard to read/maintain unless the alternative is harder to read/maintain.

I used to (many years ago) have the "goto is evil thou shalt not use goto" mentality but I then had a revaluation (or two). I have seen clean code that uses goto. I have seen code that uses goto that is more efficient than the 'equivalent' replacement code. Finally, do I really want to say that I can not use a simple instruction in a proper manner.
Finally, do I really want to say that I can not use a simple instruction in a proper manner.

:)

Perhaps the article that sourced JLBorges code. Well, almost. The code apparently comes from a LR parsing library...
http://david.tribble.com/text/goto.html

The author does prefer the look of a try-catch block over the use of goto, but then comments on the overhead.

I never use gotos, so reading them is not second nature. Probably the main reason I might argue against them.

This is easier for me to read because I feel there is a stronger connection to why functions are being called:
1
2
3
4
5
6
7
8
9
10
11
12
int parse()
{
    Token tok;
    
    while ( ( tok = gettoken() ) != END )
    {
        while ( !shift(tok) )
            if ( !reduce(tok) ) return ERROR;  
    }
    
    return ACCEPT;
}


I don't like this code because of the !shift(tok), and that it seems to put the blame of failure on reduce. However, I would have to start making assumptions about the way the functions work in order to change it.

Edit:
The strength about the Goto code is that it makes a simple state machine.
Last edited on
@JLBorges

> "goto" is such a dangerous construct, and can have such a negative impact on maintainability
> goto is a terrible thing to use.

Absolute balderdash.

If goto is really a terrible thing to use, no matter how it is used, be certain that it would have become a deprecated feature of the language.

This:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 do // read_next_item:
{
    // ...

    if( ... ) continue ; // goto read_next_item

    // ...

    if( ... ) break ; // goto no_more_items

    // ...

} while( ... ) ; // if( ... ) goto read_next_item

// no_more_items: 
do_something_with_the_items() ;



is not any more readable or maintainable than this:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 read_next_item: // do
{
    // ...

    if( ... ) goto read_next_item ; // continue

    // ...

    if( ... ) goto no_more_items ; // break

    // ...

    if( ... ) goto read_next_item ; // while( ... )
}

no_more_items: 
    do_something_with_the_items() ;




I repeat what was said bгt now relative to your statements: Absolute balderdash.

First of all some languages as for example Eiffel has no the goto statement.
Secondly the goto indeed is a dangerous statement because it ignores declarative ragions that very often only confuses readers.
Thirdly the goto statement opposite to continue and break has nothing common with control structures. If you see a break statement you can surely say that the control will be passed to the next statement after the control construction If you see a goto statement you can say nothing where the control will be passed. Even if the label is paced immediately after a control structure it does not mean that the author of the code was going to pass the control to the next statement after the control construction. He might have a purpose in future to change the body of the control structure such a way that between the control structture and the statement marked with the label will be inserted other statements. That is in fact there is no any logical link between a control structure and a goto except that the control will be passed somewhere and nobody knows where.
Last edited on
vlad wrote:
Thirdly the goto statement opposite to continue and break has nothing common with control structures. If you see a break statement you can surely say that the control will be passed to the next statement after the control construction If you see a goto statement you can say nothing where the control will be passed.


I agree completely with vlad.

JLBorges' example of a trivial insertion of goto is all fine and good until someone wants to add code after the control structure and accidentally does this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
read_next_item: // do
{
    // ...

    if( ... ) goto read_next_item ; // continue

    // ...

    if( ... ) goto no_more_items ; // break

    // ...

    if( ... ) goto read_next_item ; // while( ... )

    whoops_this_is_a_mistake();  // <-  !!!!!!!!
}

whoops_this_is_a_mistake();  // <-  !!!!!!!!

no_more_items: 
    do_something_with_the_items() ;



Apart from that the thing that makes goto REALLY dangerous is its ability to jump literally anywhere in the function, allowing you to all but completely disregard scoping rules.

Something like this:

1
2
3
4
5
6
7
8
9
10
11
12
foo();

label:

bar();

baz();

buffalo();

if( something )
    goto label;


All fine and good, until you need to modify the scope (like for a mutex or something):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
    mutexlocker m;
    m.bindto( mymutex );

    foo();

    label:

    bar();
}

baz();

buffalo();

if( something )
    goto label;  // <- BAD, jumps to code where the mutex is not locked! 



THIS is why goto is not maintainable. If there are any labels/gotos in a function... any change you make to the flow of that function requires you to carefully examine and consider the entire function rather than just the portion of the function you're actually modifying.
@Disch

THIS is why goto is not maintainable. If there are any labels/gotos in a function... any change you make to the flow of that function requires you to carefully examine and consider the entire function rather than just the portion of the function you're actually modifying.


The worst is that when you are required to make some minor changes in the function code then you in turn need to introduce one more goto statement because no control structure is linked with the goto statement. So one goto statement leads to appearing other goto statements.:)
closed account (z05DSL3A)
Disch, Vlad,

You are kind of making my point. You are doing a good job of showing how to use goto badly. How do you know that it is bad? Do you know it is bad by ignoring it and pretending it doesn't exist? Or saying well I was told that it is bad, therefore it is bad? Or do you know how to use it, understand the ramifications of using it and therefore can come up with reasons not to use it?

The only difference is, if I see somewhere where I think goto could be valid, I will investigate it further rather than dismissing it out off hand. I also have some basic rules if I want to use it.
Grey Wolf:

I never meant to say goto has no viable uses. I'm just saying its use should be tempered with caution because it's very easy to misuse.
Disch wrote:
goto label; // <- BAD, jumps to code where the mutex is not locked!

FWIW, it will fail to compile because mutexlocker apparently has non-trivial destructor. goto isn't totally dumb.
So the point is you have to worry someone might take this,

1
2
3
4
5
for (int i = 0; i < N; ++i) 
   for ( int j = 0;  j < N; ++j)
        if ( ( x = T[i][j].g() ) < e ) )
            goto end_for_for;
end_for_for:


And modify it to something like this,

1
2
3
4
5
6
7
8
for (int i = 0; i < N; ++i) 
   for ( int j = 0;  j < N; ++j)
        if ( ( x = T[i][j].g() ) < e ) )
            goto end_for_for;

//conveniently add stuff here to happen if x was never less than e

end_for_for: //now goto has crossed the line 


I agree that goto has now crossed the line. Instead, I would either do this, or consider an alternative to the goto,

1
2
3
4
5
6
7
8
for (int i = 0; i < N; ++i) 
   for ( int j = 0;  j < N; ++j)
        if ( ( x = T[i][j].g() ) < e ) )
            goto end_for_for;
end_for_for:

if (x >= e)
    //do the stuff 


But from the professionals perspective, you don't know who will later modify it, and you cannot trust that they wont abuse it.
Last edited on
If your concern is someone trying to do this,
1
2
3
4
5
6
7
8
for (int i = 0; i < N; ++i) 
   for ( int j = 0;  j < N; ++j)
        if ( ( x = T[i][j].g() ) < e ) )
            goto end_for_for;

//conveniently add stuff here to happen if x was never less than e

end_for_for: //now goto has crossed the line  


couldn't it be done without any need for the goto command
1
2
3
4
5
6
7
8
9
10
11
for (int i = 0; i < N; ++i) 
   for ( int j = 0;  j < N; ++j)
        if ( ( x = T[i][j].g() ) < e ) )
            break;

if ( x < e )
{
       // something happens
}

// continue with program 
Last edited on
1
2
3
4
for (int i = 0; i < N; ++i) 
   for ( int j = 0;  j < N; ++j)
        if ( ( x = T[i][j].g() ) < e ) )
            break;

Here you only break out of the inner loop, i is incremented, i is compared with N, if i is still less than N, you re-enter the inter loop ...
Last edited on
goto has no practical use in C++.
With the nested loop problem, there are 2 things I can see:

Consider a contrived find function, with 2 scenarios: Found the value, or; some error condition.

The first one is easy - return the value. Note we put the code into a function to do this, and it obviates the need for any convoluted break or continue statement logic.

For the second situation, In C++, could it be handled by an exception? Obviously can not do this if the language doesn't support exceptions (like C for example).

Another observation which is slightly off-topic, I heard about a CS class that was doing assembly programming. In preparation, they had to re-write a C program by only using simple if statements (no else-if or else) & goto, with no functions either. I thought that was a brilliant teaching idea - I wish I had been made to do that when I learnt assembly all those years ago.
Topic archived. No new replies allowed.
Pages: 12