Before anyone thinks about flaming me, no, I don't use goto myself. This comment got me thinking about it.

Assembler (Z80) has various jump instructions, some conditional, followed by the memory location to jump to. These differed to a call instruction in that once you jumped, you couldn't return (the address jumped from wasn't pushed onto a stack, whereas the calling address was).

With this in mind, is it wrong to use the occasional goto in code, other than for aesthetic reasons?

Jonatan Hedborg

I have to admit that i have used in on occasion, when the alternative was to re-write a loop and add a bunch of variables and if's. Not in a large program however.

It's just very ugly and makes it hard to read the code

Richard Phipps

It's not wrong to use it were it is appropriate.

TeamTerradactyl

My ideas:

I would say GOTO is a BadThing for 99% of the cases; most programmers could code well enough to never need something like this.

I have seen a GOTO in a severely-nested function, though, which seemed to do alright. It was inside, I think, 8-9 while() and for() loops, and the point of the GOTO was "Okay, the value is now true/false. Continue with the rest of the current function!" Otherwise, he would have had to test on EVERY loop whether "done == true" (or whatever), and that was too expensive when you're dealing with a loop that was close to O(2^10) or something like that.

So my answer is that you should avoid it when possible, but if you HAVE to use it, do it only for efficiency reasons like that above.

Matthew Leverton

In high level languages the use of goto can almost always be replaced by some other, more elegant solution. The only place in C where I ever use goto is to break out of some large nested loop. With some other languages, you can use the syntax break label; to avoid using a goto in such a scenario as that. Even in C, it's quite possible that such a loop can be better written as a function call that returns in place of the goto.

TeamTerradactyl

Matthew: I hadn't heard of "break label" before... That would be a useful tool if I ever start nesting...

Matthew Leverton

Both Java and D use break label;. PHP uses break level;, where level is the number of loops of which you want to break out.

ReyBrujo

Goto makes programs hard to read and analyze. The only use for goto is to break from nested cycles, yes, but most times you can prevent that by adding control variables to each of the loops.

Rampage

Goto can also be used to implement exception-like logic in languages like C. I remember having seen file access routines which had lots of potential failure points. Instead of repeating error handling code for each point, the routines used goto, which made them easier to understand.

Goalie Ca

A goto is only bad because people get lazy. Most of the time a goto is not needed (mostly only needed in low-level). Without the goto statement c and c++ are turing complete. The danger is someone could use a goto and avoid deep thinking and proper organization of the code (create a proper state machine and code it cleanly!). This is when it becomes hard/impossible to read and debug.

TeamTerradactyl

My question is this: If you use a GOTO to break out of a function, what happens to all the local variables? Are they taken out of scope, or can they still be accessed?

Oh, and I think I should start doing this from now on:

1

int main(int argc, char**argv)

2

{

3

string temp;

4

for(int i =0; i < argc; i++)

5

{

6

temp = argv<i>;

7

if(temp =="--help")

8

{

9

goto HELP;

10

HELPDONE:

11

}

12

elseif(temp =="--version")

13

{

14

goto VERSION;

15

VERSIONDONE:

16

}

17

elseif(temp =="--screenResolution")

18

{

19

goto RESOL

20

RESOLDONE:

21

}

22

elseif(...)

23

}

24

25

goto END;

26

27

HELP:

28

cout <<"You asked for help...";

29

goto HELPDONE;

30

VERSION:

31

cout <<"You're asking for the version...";

32

goto VERSIONDONE;

33

RESOL:

34

cout <<"You're asking for the screen resolution...";

35

goto RESOLDONE

36

37

END:

38

return0;

39

}

EDIT: Fixed the labels per Simon Parzer's feedback. Thanks, Simon!

Rampage

In C goto can't take you outside the scope of the current function.

Quote:

Oh, and I think I should start doing this from now on:

Oh no! Don't ever do that! That's what the switch clause is for.

Simon Parzer

Why don't you try it?

You got it all wrong BTW...

You do labels and gotos in C like this:

ThisIsALabel:;//some codegoto ThisIsALabel;

I don't know exactly what you posted but I think the syntax is wrong.In my opinion you should use goto where you need it. As long as you don't plan to share your code with others.Sometimes it even makes code simpler. I mean, I rather have a bunch of gotos and three labels than five nested loops. When I started with BASIC a long time ago I got used to GOTOs and I have no big problems with them now.In C++ or modular C the goto statement doesn't make much sense anymore, though.

HardTranceFan

Hey TT, your code put a grin on my face.

orz

Sometimes, when writing my flow control, its difficult to implement it or think of it in terms of the standard C/C++ flow control primitives of for/while/do/switch loops and function calls. Usually in such cases I'll write what I'm thinking of in terms of loops and function calls, but do most of the flow control with if...break; and if...continue; statements and a few variables declared for the sole purpose of acting as flags for the loops.

Occaisonally though, the code will become harder to maintain, and/or debug if I write it that way, so I'll use goto statements instead. That has only happened maybe 10-20 times in the last 30 thousand lines of C/C++ code I've written, and some of those cases could have been expressed as exceptions more naturally if I hadn't been trying to avoid some issue involved with exceptions in the relevant code.

Even more rarely, sometimes I'll write something where I have such a difficult time even concieving of the flow control necessary that expressing it in terms of anything other than the natural flow control primitives I concieved of it in (often gotos for something like that) would take a great deal of diagramming and analysis and just be asking for trouble, so I write it as I concieve of it. That has only happened maybe 2 or 3 times in the last 30 thousand lines of C/C++ code I've written. Perhaps I should spend the time and effort diagramming and analyzing such cases; perhaps it would improve my ability to think in terms of the usual flow control primitives. But I'm not too sure about that. Perhaps that would merely limit my thinking to things that can easily be expressed in C/C++ instead.

Rick

I have never used goto in C/C++, and the only time I've ever used it is with VB 6 for error handling. Because I never use it, I never think about it, and therefore when coding, my mind never even considers it.

Audric

Ladies and gentlemen, I give you: the computed goto in C.The &&X syntax is a DJGPPism for : "the memory address of label X".

1

#define AMC_GOTO_PCODE goto *pcode[*code_pointer]

2

3

staticconstvoid* pcode[]={

4

NULL,

5

&&AMCInt, // 1

6

&&AMCRegGlobal,// 2

7

&&AMCRegLocal, // 3

8

&&AMCRnd, // 4

9

&&AMCJump, // 5

10

&&AMCDirect, // 6

11

&&AMCExit, // 7

12

&&AMCIfnot, // 8

13

&&AMCIfjump, // 9

14

&&AMCIfdirect, // 10

15

&&AMCIfexit, // 11

16

&&AMCEnd, // 12

17

&&AMCAuto, // 13

18

&&AMCStore, // 14

19

&&AMCRecall, // 15

20

&&AMCStackup, // 16

21

&&AMCSpawn, // 17

22

&&AMCPause, // 18

23

&&AMCMove // 19

24

};

25

26

(...)

27

// start of interpretation

28

AMC_GOTO_PCODE;

29

30

(...)// some sample instructions :

31

AMCInt: // put an Integer in the register

32

code_pointer++;

33

AmEval(&currentexp,code_pointer,*(code_pointer+1));

34

code_pointer+=2;

35

AMC_GOTO_PCODE;

36

37

AMCJump: // Jump

38

code_pointer++;

39

code_pointer=*code_pointer + BOB[Actor].programstart;

40

AMC_GOTO_PCODE;

Compared to a switch() statement, this was way cooler IMHO, and the emulation time went from 3% to 2% (precision of this figure is low, though)

Johan Halmén

I've never used goto. I do think it is a bad thing. The more you use goto, the more your code differs from what is considered typical C code structure. As Matthew said, you can put the part of code in a function and have returns instead.

TeamTerradactyl

Johan, I would agree with that, unless there has to be a lot of data transfer.

Say, for example, that you have declared a bunch of data at the beginning of your function. Then, you want to test whether "a == b" and "c < d" or "e != f", etc. If you push all that data into a separate function just to do the test, it slows down the code quite a bit.

If, however, you break out of a very-nested group of loops with a GOTO, you can continue with all the data and variables you had declared/changed/etc. as if you had simply "break"-ed a bunch of times to get there...

Kitty Cat

Here's some code I have for decoding macroblocks from an MPEG-1 data stream:

It's pretty clear to see the code flow, IMO. 'goto block_start', and it goes to decode the beginning of a block. 'goto slice_start', and it goes to start decode the beginning of a series of blocks. 'goto next', and it goes to find the next block of the slice.

Compare that with a double nested loop (adding two more indentations to a good portion of the code), extra if checks, ambiguous 'continue' and 'break' commands, and needing to trace close brackets to see where something loops back to..

PS: Whee, having PMBtab0[code] in my code breaks the syntax parser.

Billybob

Quote:

How bad is a goto statement?

goto jail;

tobing

We have managed to produce way over one million lines of C++ code with the only goto statements being in the various implementations of the quicksort algorithm. So I would advocate to not use goto, except when it makes algorithms easier to read, which is most often not the case. So, IF the algorithm is easier to read and understand using goto, then use it (but with great care!)...

Kris Asick

When I was still learning how to program I would constantly use goto. Especially when I was first learning BASIC because the gosub command didn't make sense to me.

Learning C/C++ eventually taught me why goto was stupid for most situations.

But, I do still use it, though only in one very specific situation: To restart a procedure. My goto statements always return an executing procedure right back to where it started, or as close as is necessary for the purpose at hand, thus eliminating the need to have multiple nested do loops or recursion.

Goto is generally avoidable, but in the uncommon chance that it makes your code MORE readable than a do loop or if statement, then by all means, use it.

When I was coding in QBasic I used to have label for a part of code that printed some generic error message and exited the program. It was always called hell

raccoon

I think Sun has a good reason to not even include the goto-statement in Java.

Joel Pettersson

It is seldom needed, and I don't use them particularly often, but goto statements can occasionally improve both efficiency and clarity. Once in a rare while they are the best solution; when this is the case, it is nothing short of stupid to religiously avoid them. Whatever the best tool for the job is, use it.

imaxcs

Consider this code:

handle_objectdeletion:
for(multiset<CObject*, SSortObjects>::iterator it = CObjectList::o().begin();it != CObjectList::o().end();it++)// loop through STL-multiset (could be any other container as well)if((*it)->get_x()+(*it)->get_w()< CCamera::o().get_x())// check, if some statement about the object is true and delete it{
CObjectList::o().remove(it);// delete one object from the containergoto handle_objectdeletion;// we must break from the loop as the iterators might be invalid now...}

Got any advice to make it better?

HoHo

use break instead of goto and put it inside two loops, outer one loops until it has reached the end of the container.

Code not tested but in theory it should work. There are about a million other ways of doing the same thing.

[edit]Of course if the container is big then some kind of system should be used that would prevent the inner for loop to start over every time something gets deleted.

Audric

If you want to remove all the items that match the test:

multiset<CObject*, SSortObjects>::iterator it;
it = CObjectList::o().begin();while(it != CObjectList::o().end())// loop through STL-multiset (could be any other container as well){if((*it)->get_x()+(*it)->get_w()< CCamera::o().get_x())// check, if some statement about the object is true and delete it{
CObjectList::o().remove(it);// delete one object from the container
it = CObjectList::o().begin();// restart the whole loop}
it++;}

In this case, it's possible because "it = CObjectList::o().begin()" is a clean "restart", and if you delete the last element it matches the end-of-loop condition.

CGamesPlay

Ugh, learn the STL

for(multiset<CObject*, SSortObjects>::iterator it = CObjectList::o().begin();it != CObjectList::o().end();)// loop through STL-multiset (could be any other container as well)if((*it)->get_x()+(*it)->get_w()< CCamera::o().get_x())// check, if some statement about the object is true and delete it{
it = CObjectList::o().erase(it);// delete one object from the container}else
it++;

Audric

The docs I found say erase() returns void

My method of restarting is inefficient. Better to memorize a reference to the element to remove, then increase the iterator, then remove the to_be_removed element.

edit: anyway, multiset is probably a bad example, as it's one of the STL containers which does not invalidate iterators on remove.

To clarify, multisets are AssociativeContainers, and those have a void erase() (they don't need the return value anyway). The iterator erase() is part of Sequence (which is a list, vector, deque etc.). My comment about outdated docs stemmed from the fact that in the past, even Sequences had a void erase() in some compilers.

Audric

Quote:

With this in mind, is it wrong to use the occasional goto in code, other than for aesthetic reasons?

Once you start down the dark path, forever will it dominate your destiny, consume you it will.-- Yoda

To clarify, multisets are AssociativeContainers, and those have a void erase() (they don't need the return value anyway). The iterator erase() is part of Sequence (which is a list, vector, deque etc.). My comment about outdated docs stemmed from the fact that in the past, even Sequences had a void erase() in some compilers.

So if you don't have a chance to clean up a bunch of your dynamically-allocated arrays before your program does a nose-dive, they will NEVER reach the destructors for your classes and/or cleanup() code?

CGamesPlay

Quote:

So if you don't have a chance to clean up a bunch of your dynamically-allocated arrays before your program does a nose-dive, they will NEVER reach the destructors for your classes and/or cleanup() code?

All destructors on objects will be called with exit. They will not with abort, though.

TeamTerradactyl

CGamesPlay said:

All destructors on objects will be called with exit. They will not with abort, though.

But only if the dynamic array was created inside a class (which has a proper destructor)?

return(clean_all_my_stuff(0));// <-- Passes "0" to signify all went well

17

}

HoHo

Quote:

So if you don't have a chance to clean up a bunch of your dynamically-allocated arrays before your program does a nose-dive, they will NEVER reach the destructors for your classes and/or cleanup() code?

I never use exit. Errors that force program shutdown usually appear while setting up the program. I just create a function for initialization that returns some value. If it is an error it returns an error value (duh!). When I see that an error occured I simply call the function that is responsible for cleaning up and return from main afterwards.

kosmitek

very interesting subject

example:

1

while(....)

2

{

3

4

5

INSTRUCTION;

6

7

here:

8

if()

9

{}

10

elseif()

11

{}

12

13

else()

14

{

15

goto: here;

16

}

17

18

19

}

How should I delete goto ? In above example - somebody must do something, he won't go further if he won't do something, and if I delete "goto" then instructions be become executed and I don't want it - have you solution ?

Jonatan Hedborg

1

while(....)

2

{

3

INSTRUCTION;

4

5

do{

6

bool repeat =false;

7

if()

8

{}

9

elseif()

10

{}

11

else()

12

{

13

repeat =true;

14

}

15

}while( repeat );

16

}

for example.

Matthew Leverton

1

while(....)

2

{

3

INSTRUCTION;

4

do

5

{

6

if()

7

{

8

// blah

9

}

10

elseif()

11

{

12

// blah

13

}

14

else()

15

{

16

continue;

17

}

18

}while(FALSE);

19

}

TeamTerradactyl

kosmitek: both Matthew and Jonatan are correct: you would use some sort of loop (while, for, etc.) until you specify that you should break out of it (or, you can specify that you will only run it once UNLESS some condition is met).

1

bool breakInsideLoop =false;

2

while(...)

3

{

4

EXPRESSION;

5

6

while(!breakInsideLoop)

7

{

8

...

9

10

if(...)

11

breakInsideLoop =true;

12

}

13

14

... // Now, outside of the "inside" loop

15

}

Goalie Ca

Actually i've just been reading/writting some assembly and for some reason this version seems a lot nicer. I guess it depends on the audience and the style of programming and what mood your in.

here:
if(){}elseif(){}else(){
goto: here;}

but matts' version is quite nice as well. The adding an extra variable is kind of a nasty hack.

Richard Phipps

This is making my head hurt!

TeamTerradactyl

I guess we can all just start learning low-level programming and use the goto: statement a lot more ... "Let's see... push aex onto, uh... fex... then pop foo off of bar... Whoops; that should have been fee from bak. Where's my debugger again..?"

Matthew Leverton

Quote:

Actually i've just been reading/writting some assembly and for some reason this version seems a lot nicer.

But it really is a loop—it's not a one time jump. I prefer the do/while construct because of that. Ideally there would be a slimmer syntax like:

do{// ...if(foo)continue;// ...}

Either way, the use of goto (or a similar loop construct) usually indicates that you should consider rethinking your approach altogether. I think the biggest problem with relying on goto for anything is that you might end up relying on it elsewhere out of laziness.

Arthur Kalliokoski

Winduhs search just found 41 gotos in Allegro source tree on this computer...

Matthew Leverton

Most of Allegro's goto usage is for error handling. Given C's lack of exceptions, there's not always a good alternative.

Sirocco

I think the reasonable response is to say that GOTO is but one tool of many in a programmer's kit. A good programmer knows when and how often to implement the tools at his/her disposal; that is, it's there if you feel the situation warrants it.

I've used a handful of GOTO statements in the past, and I'm sure at some point in the future it will crop up once more. I've larger things to worry about

orz

I think that the anti-goto rhetoric is largely a leftover from the bygone era when many programers learned to program in asm or basic where gotos and jmps were natural. People who started with C or higher level languages usually use higher level flow control primitives because, for most code, they're easier to write, maintain, and think in.

Quote:

Most of Allegro's goto usage is for error handling. Given C's lack of exceptions, there's not always a good alternative.

That's what longjmp() is for. (/me is mostly joking)

edit: first paragraph was edited for clarity

kosmitek

I try change this code as you say (it is also in ATTACHMENT) - but when I changed it wrong run - for example if I press "M" then pawn doesn't run BUT when I next press "->" then it goes 2 times !

Thanks LennyLen, but it is also wrong because:please start this game, please press "m" or other letter on keyboard 5 or more times and you see that information: "You throw: X " - and that X(number of eyes) it will be change - and X(number of eyes) should change ONLY when somebody press "->" or "<-", when somebody press something else X(number of eyes) shouldn't change - it is a problem which can be solved only when wy use "goto" - that I think.

LennyLen

This new run_game() function "fixes" the problem of it rolling when other keys are pressed. I'll leave it up to you to figure out how to only display information when M is pressed.

WOOOW !!!!! Run very good - I must seeing through very attentively - thank you LennyLen

--------------------------ups - pawn after throw bone doesn't go after right fields - I tried change it but only when I use "goto" was okay

LennyLen

Here's a version I rewrote that extends the player class so that it now stores what tile the player is on, as well as the result of the latest roll. I also added a method to reroll the dice. The program now relies less on global variables, and is a little more object oriented.

I don't normally use C++, so there may be more efficient ways of doing things than I what I do.

By the way, I've left the logic of your game untouched, as I'm not 100% certain what you're trying to do. I'm curious as to why there's a lot more code for when the player presses left then for when they press right.

LennyLen somewhere is little mistake - pawn after throw bone doesn't go after right fields - I tried change it but only when I use "goto" was okay

LennyLen

Quote:

LennyLen somewhere is little mistake - pawn after throw bone doesn't go after right fields - I tried change it but only when I use "goto" was okay

The program I wrote behaves exactly as the one you wrote, so if there's a problem, it's in your logic. I've attached both your original program (I recompiled it to use the dynamic library so it was smaller) and the version I wrote so you can see for yourself that they behave the same.

TeamTerradactyl

Gee...

This sounds almost like the program I provided earlier to you, kosmitek, before you added the "player" class. Can't for the LIFE of me figure out why that code couldn't be used... It was re-written to be very understandable, use the exact same keys, handle the exact same logic...

Why not just extend what was already written for you and use that? It's not as if the code doesn't compile...

LennyLen, I don't know if you saw that earlier post or not (in the other thread, no less), but you may be able to use it. If not... shrug.

kosmitek

TeamTerradactyl yes, but I didn't use your earlier program because he also was wrong In my program when I throw for example 3, pawn go 3 fields and in yours programs pawn is strange going - somewhere in your programs is little mistake, I must use "goto" in your program and only then pawn going right.

Paul Pridham

OK... you guys are posting about how GOTO is ugly and hard to read, and then post this as some sort of counter-example:

for(multiset<CObject*, SSortObjects>::iterator it = CObjectList::o().begin();it != CObjectList::o().end();)// loop through STL-multiset (could be any other container as well)if((*it)->get_x()+(*it)->get_w()< CCamera::o().get_x())// check, if some statement about the object is true and delete it{
it = CObjectList::o().erase(it);// delete one object from the container}else
it++;

I mostly use GOTOs for function-level error handling. Setting a flag, checking it in multiple points to break a loop/nest is slower and less efficient than a goto.

Bob

Quote:

You guys are posting about how GOTO is ugly and hard to read, and then post this as some sort of counter-example:

I think in my program must be "goto", without "goto" my program isn't run good.

LENNY LEN - YOUR IDEA WITH 3 files: main.cpp; player.h; player.cpp, one table; and globall variables ARE WONDERFUL - WITHOUT THAT I MUSTED (MUST IN THE PAST ?) WRITE EVERYTHING IN ONE BIG FUNCTION AND NOW I HAVE MANY LITTLE FUNCTIONS - THANK YOU - THIS IDEA IS VERYYYYY GOOD - THANK YOU LENNY LEN FOR YOUR IDEA - I USE YOUR IDEA (but I had use "goto") AND I ADD GLOBAL TABLE - ONLY ONE TABLE !!! - THANKS YOU !!!!!!!!! YOU ARE WONDERFUL - THANK YOU !!!!!

Simon Parzer

Quote:

MUST IN THE PAST ?

had to

Example: Because I forgot to turn off capslock I had to slap myself in the face several times.

LennyLen

Quote:

LennyLen, I don't know if you saw that earlier post or not (in the other thread, no less), but you may be able to use it. If not... shrug.

Yeah I saw it. Most of my code was actually from when I rewrote the program last time kosmitek posted about it a few weeks ago.

Quote:

TeamTerradactyl yes, but I didn't use your earlier program because he also was wrong In my program when I throw for example 3, pawn go 3 fields and in yours programs pawn is strange going

The real problem was that you didn't explain very well what you were trying to do, and it's hard to tell from your code exactly what you are doing.

Now that I'm pretty certain that I know what you're trying to do, I've changed the logic to reflect this. I've attached the working code (the changes were to the run_game() function) and an executable. There's still no need for goto.

edit:

Don't rely too much on global variables. They certainly have their uses, but if you have too many of them, it makes the program harder to follow and less modular. There's usually a more elegant solution.

Dustin Dettmer

I think gotos can add much needed clarity to complex operations and I honestly think they are the shit. goto Failure is about as clear as you can get. There are a number of other completely valid and wonderfully clear uses of gotos.

The ability for a language feature to be misused does not render the feature obsolete.

kosmitek

now it runs ideal WITHOUT "GOTO" - LENNY LEN YOU ARE GENIUS !!!!!!

BAF

Your shift key is sticking again.

FMC

Thanks for the pretty code Bob, i didn't know you could handle it that way!

What i previously did:

//fl...ake is a vector iterator of the same type as snow//snow is a vectorfor(fl = snow.begin(); fl!=snow.end(); fl++){if(fl->dead()){
snow.erase(fl);
fl--;}}

Is this wrong or bug prone?

CGamesPlay

Quote:

Is this wrong or bug prone?

Yes, fl is invalid when it is erased: you can't increment or decrement. In practice, however, it will work for vectors so long as you are not erasing the final element.