Sign in to follow this  

To goto or not to goto?

This topic is 2302 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.


Recommended Posts

I find them useful to do cleanup in functions that can fail, so I dont have to free all the resources everywhere, I can just goto the end, and put all the frees there

Share this post


Link to post
Share on other sites
I think you need to define the context of this question; in some languages you would be highly restricted if there weren't any "goto"s. Making some assumptions, I think Dijkstra's opinion on this matter might be an interesting read ("Edgar Dijkstra: Go To Statement Considered Harmful" [url="http://wwwens.uqac.ca/~flemieux/PRO102/Dijkstra_Goto.pdf"]http://wwwens.uqac.c...jkstra_Goto.pdf[/url])

I'm curious about the intent behind the poll in this thread; are you meaning to form an opinion based on the general consensus?

Share this post


Link to post
Share on other sites
I've used [b]one [/b]goto in the say... 18 years I've been programming. It was a throwaway test app that I had to trigger cleanup code before exiting the function and had done it so slapdash that a finally block wouldn't deal with it; and it [i]amused me[/i] to write such horrible code.

If you used a goto in production code I would fire you on the spot.

Share this post


Link to post
Share on other sites
I use [b][font="Courier New"]goto[/font][/b]. Quite a bit.

I use it exclusively in object-oriented C programming, because C lacks useful constructs such as RAII and exceptions. It is better to have a forward-jumping goto into a sequence of rollback operations as you initialize members on your constructor code than any other way of handling failures. The use of [b][font="Courier New"]goto[/font][/b] gives clarity and structure where no other construct can.

For those of you who are too young to understand what Dijkstra wrote, his poins was that alternatives to [b][font="Courier New"]goto[/font][/b] should be emphasized and chosen in many situations. At the time, such as when I was a student, much code was written in non-structured langauges like FORTRAN IV or BASIC, and the use of [b][font="Courier New"]goto[/font][/b] was required by the language itself. Most programs were [i]spaghetti code[/i]. Dijkstra was involved in designing a new language, one that could be used to teach and to reason about computing -- he was not advocating a dogmatic methodology for future generations.

When a dogmatic anti-goto zealot tells you never to use that control construct, stop and ask for a clarification on the reasons why. If he or she can not tell you any reason other than the [i]ipso dixit[/i] of "Dr. Dijkstra wrote a paper saying it was harmful," ignore them and any other advice they give.

Share this post


Link to post
Share on other sites
[quote name='patrrr' timestamp='1312666809' post='4845554']in some languages you would be highly restricted if there weren't any "goto"s[/quote]
I see your point.

[quote name='patrrr' timestamp='1312666809' post='4845554']I'm curious about the intent behind the poll in this thread; are you meaning to form an opinion based on the general consensus?[/quote]
The reason I made this poll is because i personally use them exactly this way:

[quote name='zacaj' timestamp='1312665780' post='4845550']I find them useful to do cleanup in functions that can fail, so I dont have to free all the resources everywhere, I can just goto the end, and put all the frees there[/quote]
... and I got curious about whether people in general avoid them at all cost, or if there were indeed others who think they are the right solution in some (special) situations.

Share this post


Link to post
Share on other sites
[quote name='zacaj' timestamp='1312665780' post='4845550']
I find them useful to do cleanup in functions that can fail, so I dont have to free all the resources everywhere, I can just goto the end, and put all the frees there
[/quote]

Isn't that more or less what exceptions are for?

Share this post


Link to post
Share on other sites
[quote name='ProgrammerZ' timestamp='1312669641' post='4845586']
[quote name='zacaj' timestamp='1312665780' post='4845550']
I find them useful to do cleanup in functions that can fail, so I dont have to free all the resources everywhere, I can just goto the end, and put all the frees there
[/quote]

Isn't that more or less what exceptions are for?
[/quote]

C doesn't have exceptions (or constructors/destructors).

Exceptions might also be non-deterministic and cannot be used for hard real-time system or in a system which needs to behave deterministically with respect to error, so propagation doesn't add extra value beyond error codes.

See Linux kernel coding guidelines which describe the idiomatic error handlers. In C++, one would use objects, preferably RAII in combination with exceptions instead. The non-determinism consideration remains, but is rarely required.

Share this post


Link to post
Share on other sites
Actually in C#, I believe it is valid to use goto statements when dealing with switch statements that share the same code. In C# you cannot do

[code]
switch(var)
{

case a:
case b:
case c:
some code...
}[/code]

Share this post


Link to post
Share on other sites
[quote name='ProgrammerZ' timestamp='1312669641' post='4845586']Isn't that more or less what exceptions are for?[/quote]
In addition to what Antheus wrote about exceptions not existing in C, the concept of goto is actually very natural to the processor, and for that very reason they are usually translated into a single jump instruction, if any:

Goto version
[code]
int test (int i)
{
if(i)
goto ERROR;

return 1;

ERROR:
return 0;
}
[/code]
[source]
?test@@YIHH@Z (int __fastcall test(int)):
00000000: xor eax,eax
00000002: test ecx,ecx
00000004: sete al
00000007: ret
[/source]
Exception version
[code]
int test (int i)
{
if(i)
throw(0);

return 1;
}
[/code]
[source]
?test@@YIHH@Z (int __fastcall test(int)):
00000000: push ecx
00000001: test ecx,ecx
00000003: je 0000001C
00000005: push offset __TI1H
0000000A: lea eax,[esp+4]
0000000E: push eax
0000000F: mov dword ptr [esp+8],0
00000017: call __CxxThrowException@8
0000001C: mov eax,1
00000021: pop ecx
00000022: ret
[/source]

Share this post


Link to post
Share on other sites
The objective should always be to have clean, readable, maintainable code that works. Use whatever programming construct is most appropriate on a case-by-case basis to achieve this. Sometimes it's an if, sometimes it's a loop, sometimes an exception handler, sometimes even a dreaded goto. You won't know this until you come to design the code, so don't presume in advance that Thou Shalt Not ever do things a certain way, and always remember that you can sometimes create an even bigger mess by attempting to avoid a particular construct, or by attempting to shoe-horn an algorithm into an unsuitable construct.

Share this post


Link to post
Share on other sites
[quote name='tariqwalji' timestamp='1312670937' post='4845593']
Actually in C#, I believe it is valid to use goto statements when dealing with switch statements that share the same code. In C# you cannot do

[code]
switch(var)
{

case a:
case b:
case c:
some code...
}[/code]

[/quote]

Actually, that's not quite true in C#.
[code]
// you can do this
switch (x) {
case 1:
case 2:
case 3:
// stuff
break;
}

// but not this
switch(x) {
case 1:
//stuff
case 2:
// more stuff
case 3:
// even more stuff
break;
}[/code]

Share this post


Link to post
Share on other sites
[quote name='Dragonion' timestamp='1312672020' post='4845598']
[quote name='ProgrammerZ' timestamp='1312669641' post='4845586']Isn't that more or less what exceptions are for?[/quote]
In addition to what Antheus wrote about exceptions not existing in C, the concept of goto is actually very natural to the processor, and for that very reason they are usually translated into a single jump instruction, if any:

Goto version
[code]
int test (int i)
{
if(i)
goto ERROR;

return 1;

ERROR:
return 0;
}
[/code]
[source]
?test@@YIHH@Z (int __fastcall test(int)):
00000000: xor eax,eax
00000002: test ecx,ecx
00000004: sete al
00000007: ret
[/source]
Exception version
[code]
int test (int i)
{
if(i)
throw(0);

return 1;
}
[/code]
[source]
?test@@YIHH@Z (int __fastcall test(int)):
00000000: push ecx
00000001: test ecx,ecx
00000003: je 0000001C
00000005: push offset __TI1H
0000000A: lea eax,[esp+4]
0000000E: push eax
0000000F: mov dword ptr [esp+8],0
00000017: call __CxxThrowException@8
0000001C: mov eax,1
00000021: pop ecx
00000022: ret
[/source]
[/quote]

The problem is your two pieces of code do not show the same operational construct; one is error code returning, the other is error throwing. I see the intent but the code is not a true representation of solving the same problem as the exception version does more work.
(Sidebar; technically the code is poor anyway as your latter example shows that 'error' is an exceptional case therefore you should invert the test and assume 'succeed' occurs more often... just sayin' ;))

Personally I'm not against 'goto', however once I stopped coding in BASIC and Assembly and became mainly a C++ coder I have found no practical reason (as yet) to use it in my own code when other methods serve me better.

Share this post


Link to post
Share on other sites
[quote name='Antheus' timestamp='1312669549' post='4845584']
[quote]If you used a goto in production code I would fire you on the spot.[/quote]

Which is fine, since I don't want to belong to religious organizations based around dogmas conjured on word-of-mouth lore.

I can't imagine what would happen if someone dared overload an operator.
[/quote]

Sorry, I should've clarified. I work currently in C# house. If you're using that language (as opposed to C/basic/etc where options are lessened) and still manage to mangle your design sufficiently that goto is your best option... and then proceed to use goto anyway instead of cleaning up your design; then you've shown yourself as someone not to trust in the codebase.

The same thing would happen if you made a 2000 line method by hand or a class with 100 public parameters. They're not dogma, they're definitive signals that either you don't care or you're a bad programmer.

Share this post


Link to post
Share on other sites
I agree with Phantom, the use of goto is never actually needed. But, that doesn't mean that it shouldn't be used right?
There is nothing wrong with goto in-of-iitself, and yes goto's are natural to the compiler, and execution flow, on and on.

The problem with goto is that the intent of the code is not clear, which will lead to bugs if it is used often. The whole point behind creating a function is to separate logical pieces of code, and or reuse redundant code. A function shows a clear separation of code from the rest. I suppose a good example would be to try and create a program without using functions, just goto statements. That program would be a very bad program. Now, I realize this is an extreme, but this extreme shows how the use of the goto statement can be bad. If resources must be freed, then a function should be created to free resources and it should be called. In this way, all the freeing of resouces occurs in a single place, so if there is a memory leak, you should be able to find it quickly. A goto statement is bad because it means many more lines of code will have to be altered if a program flow changes. If the goto's are removed, minimal code changes are required because the program is separated into logical parts which are easy to modify on their own.

I realize that people will still use goto's, but it leads to more confusion and bugs than it helps. Ask anyone who has worked on large projects before if the use of goto is a help or a hindrance and I know it will be that goto's do not help in any case what so ever. Programming is about structure and organization, and goto's really do break that concept.

If a person is working on their own code by themselves, use goto all you want, but if you are working on a project with others, do not use goto. I agree with
Telastyn when he said, "If you used a goto in production code I would fire you on the spot." This is soo true

Share this post


Link to post
Share on other sites
I guess I am a heretic, but I use goto in other situations that haven't been mentioned here. The most common is something like this:
[code]for (int i=0; i<n; ++i) {
switch (some_array[i]) {
case 0:
//...
break;
case 1:
if (some_condition())
goto DONE; // Break out of the loop, in a situation where `break' would just break out of the switch block.
break;
//...
}
}
DONE:
//...[/code]

Share this post


Link to post
Share on other sites
[quote name='alvaro' timestamp='1312691317' post='4845658']
I guess I am a heretic, but I use goto in other situations that haven't been mentioned here. The most common is something like this:
[code]for (int i=0; i<n; ++i) {
switch (some_array[i]) {
case 0:
//...
break;
case 1:
if (some_condition())
i=n;// DONE!!!
break;
//...
}
}
//...[/code]
[/quote]

Share this post


Link to post
Share on other sites
[quote name='smasherprog' timestamp='1312692331' post='4845662']
[quote name='alvaro' timestamp='1312691317' post='4845658']
I guess I am a heretic, but I use goto in other situations that haven't been mentioned here. The most common is something like this:
[code]for (int i=0; i<n; ++i) {
switch (some_array[i]) {
case 0:
//...
break;
case 1:
if (some_condition())
i=n;// DONE!!!
break;
//...
}
}
//...[/code]
[/quote]
[/quote]


That's cheating xD

There are other loops, that can explain better the intentions:


[code]do {
switch (some_array[i]) {
case 0:
//...
break;
//...
++i;
} while (i < n && !(some_array[i] == 1 && some_condition()));
}
//...[/code]

Share this post


Link to post
Share on other sites
[quote name='smasherprog' timestamp='1312692331' post='4845662']
[quote name='alvaro' timestamp='1312691317' post='4845658']
I guess I am a heretic, but I use goto in other situations that haven't been mentioned here. The most common is something like this:
[code]for (int i=0; i<n; ++i) {
switch (some_array[i]) {
case 0:
//...
break;
case 1:
if (some_condition())
i=n;// DONE!!!
break;
//...
}
}
//...[/code]
[/quote]
[/quote]
Now you are just avoiding goto for the sake of avoiding goto. You didn't improve readability at all.

Share this post


Link to post
Share on other sites
[quote name='Drathis' timestamp='1312698807' post='4845688']
Now you are just avoiding goto for the sake of avoiding goto. You didn't improve readability at all.
[/quote]

That seems to be a common thing. At one job I kept running into code that replaced gotos with while(1) break constructs, ie

[code]
if ( a_fails)
goto cleanup;

if ( b_fails)
goto cleanup;
[/code]

turned into
[code]
while (1)
{
if (a_fails)
break;

if (b_fails)
break;

break;
}
[/code]

Of course this is even less readable and half the time people would forget the final break. The "optimized" version was using a "do while(false)" loop.

It's what happens when someone blindly follows the "thou shalt not goto"-chants by trying to emulate a goto with weird constructs instead of trying to design his code in a way that doesn't need a goto (or pseudo-goto) in the first place.

Yet, if I ever DO run into a situation in C++ where goto is the cleanest and most readable option, I will happily use it. Didn't happen in over 12 years, though.

Share this post


Link to post
Share on other sites
I think the ones against goto always use the worst examples of gotos. I don't really get the "intent of code is not clear" argument (that case example in this thread was ironically a pretty good example that avoiding that goto made the code less clear and more error-prone. What if I wanted to examine 'i' after the loop? what if I wanted to add some stuff after the switch but inside the loop later?).

Intent of code is not clear when used in the most idiotic ways (like long jumps (code-wise), jumping back and forth, variable declarations messed with gotos, replacing more sophisticated constructs with gotos, having too big functions, jumping into loops/conditional-blocks maybe even jumping in and out of functions). Other than those, it's so clear for me: "go to that line". If you have a small function (which you should) and have some other "rules" of use (like label is after goto, no variable declarations between the two if they are in the same scope) then I can't think of any clearer ways to control program flow. It's just as clear as "break" for example (some argue that break is evil too. Well, good luck with the 5th 'foo' variable just to control flow...). "Continue" is a much more unclear solution IMHO.

Of course, these stuff should not be in the "framework" code. I don't know the proper terms. So the main loops, or "high level stuff" shouldn't have these. This high level stuff should be well designed and should be awesome. But I can't really think of a way to write "neat" or "well designed" code for a complex algorithm for example (before you bring up the "design it better" argument).

Okay, I'm a person who doesn't really give a shit about the implementation of "black box" (pure) functions. If they work, it's time to move on. I don't give a fuck (and I wouldn't give a fuck if I worked in a team) how that function is implemented if it's not my task to implement it. All I care about its interface and performance.

Share this post


Link to post
Share on other sites
[quote name='szecs' timestamp='1312706072' post='4845715']I think the ones against goto always use the worst examples of gotos.[/quote]
And for that reason, here is an example where I personally think it makes good sense to use goto statements (like a replacement for a small inline function):
[source]
static MyClass*MyClass::createInstance(void)
{
MyClass*inst=null;

if(!(inst=new MyClass()))
return null;
if(!(inst->object1=new Object1()))
goto FAILED;
if(!(inst->object2=new Object2()))
goto FAILED;
if(!(inst->object3=new Object3()))
goto FAILED;
if(!(inst->object4=new Object4()))
goto FAILED;

return inst;

FAILED:
{
delete inst->object1;
delete inst->object2;
delete inst->object3;
delete inst->object4;
delete inst;

return null;
}
}
[/source]
Surely you could avoid using them like this:

[source]
static inline void MyClass::failed(MyClass*inst)
{
if(inst)
{
delete inst->object1;
delete inst->object2;
delete inst->object3;
delete inst->object4;
delete inst;
}
}
static MyClass*MyClass::createInstance(void)
{
MyClass*inst=0;

if(!(inst=new MyClass()))
return null;

if(!(inst->object1=new Object1()))
{
failed(inst);
return null;
}
if(!(inst->object2=new Object2()))
{
failed(inst);
return null;
}
if(!(inst->object3=new Object3()))
{
failed(inst);
return null;
}
if(!(inst->object4=new Object4()))
{
failed(inst);
return null;
}

return inst;
}
[/source]
... but in this case I honestly think the goto version is the more elegant/clean solution.

PS: I know you should use the 'static' keyword in the function declaration/prototype, not in the definition/implementation, but I inserted them here to avoid making a class definition just to show that these functions are static.

EDIT: Or perhaps a combination providing the opportunity to re-use the delete functionality:
[source]
static inline void MyClass::deleteInstance(MyClass*inst)
{
if(inst)
{
delete inst->object1;
delete inst->object2;
delete inst->object3;
delete inst->object4;
delete inst;
}
}
static MyClass*MyClass::createInstance(void)
{
MyClass*inst=null;

if(!(inst=new MyClass()))
return null;
if(!(inst->object1=new Object1()))
goto FAILED;
if(!(inst->object2=new Object2()))
goto FAILED;
if(!(inst->object3=new Object3()))
goto FAILED;
if(!(inst->object4=new Object4()))
goto FAILED;

return inst;

FAILED:
{
deleteInstance(inst);
return null;
}
}
[/source]

Share this post


Link to post
Share on other sites

This topic is 2302 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this