Click to See Complete Forum and Search --> : goto


AlexanderCZ
October 17th, 2002, 08:07 AM
What is bad on using goto statement???
I often heard:"if you use goto,you can't make good programs.."
What do you think about it?
I think you are better programmer when you can use goto statement then somebody who can't use it...;)

Sput
October 17th, 2002, 08:26 AM
I was also taught Goto statements are bad. They are evil constructs that allow program flow to just jump practically anywhere.

But I do use them once in a GREAT while. Why? Lets say you have a method that is allocating a bunch of resources/memory. And at anypoint, you could receive a error condition. To keep the method clean/readable, I have used a goto statement to jump to the end of the method. This way I have one exit point of the method that frees everything up. Less chances for memory leaks.


Disclaimers:
a) The below is a VERY simple example. Just here for demonstration
b) There are other ways of solving the memory cleanup without using gotos
b1) re-organize without goto
b2) exception handling
b3) smart pointers concepts


void MyFunc()
{
type* p1 = NULL;
type* p2 = NULL;

p1 = new type[50];
if (something bad)
goto FuncExit;

p2 = new type[2];
if (something bad)
goto FuncExit;

do some other code with other possible exit points

FuncExit;
delete [] p1; // works if p1 is NULL;
delete [] p2;
}

I can't think of an example of me using goto in my current project. Buts it there in my bag of tricks.

PaulWendt
October 17th, 2002, 08:30 AM
Let the debate begin.

Honestly, anyone can use goto; that's part of the problem. When
used improperly, goto can lead to circuitous and confusing code.
When used carefully, goto can save time and ... <gasp> ... even
make things more readable. The problem is that everyone has
different opinions on what proper goto usage is. Also, most
things can be done without goto with no problem so more
tradational control structure are preferrable in my opinion.

One instance <I> consider goto useful is if you're in two [or more]
loops .. and from the inner loop, you want to break out to the
outer loop. You could just set the outer loop's terminating
condition to get out of that loop, too.

The big problem with goto and C++ is that goto will skip
destructor calls if you goto a spot that's out of a created
object's scope.

Given the inherent complexity and potential misuse, I don't use
goto. I WOULD use it if I found an instance where I really needed
it ... but I'm usually able to get by just fine with the other features
of the language. The more low-level you get with your
programming, the more useful you might find goto. I try to
program on as high a level as I can most of the time :)

--Paul

dude_1967
October 17th, 2002, 10:49 AM
Hi gurus,

Generally we do not use goto in our group. We discourage ist use but do not forbid it.

We actually do use goto for improved readibility and clarity when dealing with assembler labels in mixed assembler / C / C++ development of hard real-time operating systems.

There are other flow-control statements such as break and continue. Along the same lines, some radical developers even try to eliminate the use of these (relatively) harmless flow controls. I've got no real opinion here.

Chris.

:)

jflegert
October 17th, 2002, 11:01 AM
Paul,

The big problem with goto and C++ is that goto will skip
destructor calls if you goto a spot that's out of a created
object's scope.

Could you expand on this? I just did a little test code (I had a goto exit a for loop with a variable defined in the for loop) and the destructor got called.

Thanks,
John Flegert

Graham
October 17th, 2002, 11:02 AM
Originally posted by Sput
[...] Lets say you have a method that is allocating a bunch of resources/memory. And at anypoint, you could receive a error condition. To keep the method clean/readable, I have used a goto statement to jump to the end of the method. This way I have one exit point of the method that frees everything up. Less chances for memory leaks.

No, no, no (at least, in the C++ world). You have said that there are other ways of solving memory cleanup. Quite right, RAII (Resource Acquisition Is Initialisation) reduces (or eliminates) resource leaks. Do not even suggest the cleanup on exit "solution" - it isn't a solution: don't ever do it. All the points you make under (b) are valid reasons to never use the "cleanup on exit" approach. In fact, b2 is enough on its own:

void MyFunc()
{
type* p1 = NULL;
type* p2 = NULL;

p1 = new type[50];
if (something bad)
goto FuncExit;

p2 = new type[2]; ***
if (something bad)
goto FuncExit;

do some other code with other possible exit points

FuncExit;
delete [] p1; // works if p1 is NULL;
delete [] p2;
}

Suppose the "new" at *** throws an exception (like it's supposed to do, VC++ notwithstanding), or the bulk code throws. p1 (and, possibly, p2) does not get deleted - you have a resource leak. The only way to avoid this is to allocate the resource in an object's constructor and release it in the destructor, because the the destructor will always be called.

void MyFunc()
{
std::vector<type> p1;
std::vector<type> p2;

p1.reserve(50);

p2.reserve(2); ***

do some other code with other possible exit points
and possible exceptions thrown
}

This code is resource safe. No matter how the function exits, the memory grabbed by p1 and p2 will be freed - and any destructors for objects stored in the vectors will be called.

Putting in a goto to a mythical cleanup section gives a false sense of security - it is not safe.

So, the one "use" of goto that you advocate is unsafe and unnecessary.

Paul: I would suggest that goto out of a nested loop reduces readability - others may disagree: I don't want to argue the point. I would also suggest, though, that it indicates a design flaw. I've written some pretty hairy nested loops in my time and (apart from the bad old days of FORTRAN), I've not found a need for goto. in fact, in recent times, I've even managed to avoid break and continue in loops. There are no hard and fast rules, but often factoring out inner loops and conditional sections of loop bodies dramatically increases readability and maintainability. In fact, I'll stick my neck out here: if you want to use a goto, consider refactoring (or using RAII properly) instead.

Sput
October 17th, 2002, 11:46 AM
Graham: Sorry about the example. Thats what the disclaimer was for. Especially the first one (A). I should of given a better (more valid) example. Maybe one not using memory, and one such that all paths don't automatically work. :o :D

Looking at my 30-second-to-write piece of source code, your comments about it are correct. :cool:

The only point I was trying to make is that if you allocate/use resources ( memory or OTHER ) and your method is coded to have multiple exit points, one use of the GOTO statement is to jump to the end and have one place for resource cleanup/release and one method/function exit point. Situations like this usually end up happening due to multiple conditions or loops. (although, you can always take a step back and see if you can restructure the source :) )

oh yea... By other resources, I'm thinking if could be files (close or delete), threads, etc... I don't know. Theres always many ways to solve the same problem. I just don't dismiss the use of Goto. Although, I don't always recommend or use it either.

One question though:
Suppose the "new" at *** throws an exception (like it's supposed to do, VC++ notwithstanding), or the bulk code throws. p1 (and, possibly, p2) does not get deleted - you have a resource leak. The only way to avoid this is to allocate the resource in an object's constructor and release it in the destructor, because the the destructor will always be called.
If I understand what you are stating, If you use the smart pointer concept (allocate in constructor, free in destructor) then once the exception is thrown, all destructors in the method are called. Is this true? Or just whats in the Try block. I don't use exceptions that much (nor is it encouraged at my work to do so). Only when calling code that uses exceptions.

As far as the smart pointers concept. Thats usually what I do. :) This concept can even be taken as far as to create a template utility classes for selecting GDI objects into the DC (in ctor) and releasing in dtor (destructor). hhmm.. I can vaguely remember dealing with this in complicated c functions (in my sdk days) using Gotos. :o :o

galathaea
October 17th, 2002, 12:32 PM
The keyword goto is a there if you need it, so don't be afraid to use it. There are better design implementations possible, though, so if you are looking for something that is consistent and readable, I would look into things like termination handlers. Especially for cleanup routines. Wrapping some code in __try, __finally will help if you don't have any need for strong c++ handling of scope and destructors.

Graham
October 17th, 2002, 01:24 PM
Originally posted by Sput
Graham: Sorry about the example. Thats what the disclaimer was for. Especially the first one (A). I should of given a better (more valid) example. Maybe one not using memory, and one such that all paths don't automatically work. :o :D

... and my point is that you'll waste an awful lot of time looking for a better or more valid example. There aren't any. The set of situations in which the use of goto is elegant, readable, maintainable and correct is vanishingly small.

The only point I was trying to make is that if you allocate/use resources ( memory or OTHER ) and your method is coded to have multiple exit points, one use of the GOTO statement is to jump to the end and have one place for resource cleanup/release and one method/function exit point. Situations like this usually end up happening due to multiple conditions or loops. (although, you can always take a step back and see if you can restructure the source :) )

... and my point was that it doesn't address the whole problem. You can still leak resources, so do do it properly (with RAII) or don't bother.

If I understand what you are stating, If you use the smart pointer concept (allocate in constructor, free in destructor) then once the exception is thrown, all destructors in the method are called. Is this true? Or just whats in the Try block. I don't use exceptions that much (nor is it encouraged at my work to do so). Only when calling code that uses exceptions.

Absolutely - that's why RAII works. As soon as a fully constructed object goes out of scope, for whatever reason (short of something disastrous, in which case it won't matter), its destructor will be called.

As far as the smart pointers concept. Thats usually what I do. :) This concept can even be taken as far as to create a template utility classes for selecting GDI objects into the DC (in ctor) and releasing in dtor (destructor). hhmm.. I can vaguely remember dealing with this in complicated c functions (in my sdk days) using Gotos. :o :o
RAII is about managing ALL your resources, not just memory. Don't restrict yourself to smart pointers: GDI resources, locks, whatever: if it's a resource that needs managing, RAII handles it. That's why I don't like Garbage Collectors: they may well manage memory, but in the process you lose deterministic destructors, so all the other resources that could have been managed are now subject to leaking. Here's an example that doesn't involve memory at all:

class DatabaseLock
{
public:
DatabaseLock(Database* db)
{
// Obtain a lock on the database to prevent concurrent write
db->StopOthersWriting();
}
~DatabaseLock()
{
// Release the lock
db->AllowOthersToWrite();
}
};

void WriteToDatabase(Database* db)
{
DataBaseLock lock(db);

// Write to database
} // Lock released as lock object goes out of scope.

Imagine that in the process of writing to the database, the system throws an exception....
How does the above compare with:

void WriteToDatabase(Database* db)
{
db->StopOthersWriting();

// Write to the database

Done:
db->AllowOthersToWrite();
}

How long will that database stay uncorrupt?

Graham
October 17th, 2002, 01:31 PM
Originally posted by galathaea
The keyword goto is a there if you need it, you don't need it so don't be afraid to use it. I'm not afraid to use it - I choose not to contaminate my code with it. There are better design implementations possible, though, Absolutelyso if you are looking for something that is consistent and readable, I would look into things like termination handlers.Why? Especially for cleanup routines.Use RAII. What are cleanup routines? Wrapping some code in __try, __finallyNo such keywords in C++ will help if you don't have any need for strong c++ handling of scope and destructors. I don't understand that last statement - you always have to consider and deal with scope. You may only ever use simple classes that have trivial destructors, but at some point you'll have more complex needs.

jfaust
October 17th, 2002, 01:32 PM
The keyword goto is a there if you need it, so don't be afraid to use it.


That's the problem. It's a very simple concept to use. So simple that a beginner can use it, and feel confident he/she knows what's happening. It's so simple that it might seem like the way to go. I like the "simple is best" approach. I preach the K.I.S.S. principal. That is not the case here.

I think if you are ever considering using a goto, that you should be afraid. You should step back and take a serious look at it. You should discuss it with a colleague. You should find different solutions, and convince yourself that this is really best. And even then, you should document it heavily. I've spent enough time sifting through old (I mean old) FORTRAN, that gotos make me cringe.

I suppose you could come up with a situation where a goto really does solve the problem better than other solutions. I don't know. I can't think of one, and I have never seen one. That doesn't mean it doesn't exist.

Jeff

PaulWendt
October 17th, 2002, 01:47 PM
Originally posted by jflegert
Paul,

Could you expand on this? I just did a little test code (I had a goto exit a for loop with a variable defined in the for loop) and the destructor got called.

Thanks,
John Flegert

Oops :) What I meant was the "goto" concept. Um ... in other
words, there are things called "nonlocal goto's"; these are the
setjmp() or longjmp() functions. If you use THESE functions, your
destructors will not get called [depending, of course, on your
compiler]. So, the 'goto' itself will let destructors be called, but
certain goto constructs won't.

I guess this discussion is about the 'goto' keyword and not the
concept of "goto" statements. Either way, I don't use very many
goto-type statements.

--Paul

AnthonyMai
October 17th, 2002, 01:49 PM
Graham said:

The big problem with goto and C++ is that goto will skip
destructor calls if you goto a spot that's out of a created
object's scope.


That's a reasonable imagination of what could happen. But unfortunately it is NOT TRUE. Don't spread the rumor. Check the fact first, Graham!

I am not sure whether it is in the standard or not. But all compilers I used are smart enough to figure out that a "goto" would jump to an outside scope, and it will call appropriate destructors for objects declared in inside scopes. Same as when you call "return" it will call all appropriate destructors.

And compilers are also smart enough to prevent you from "goto" an inside scope. The only place you can go to are the places within the same scope, or outside current scope but still within the function scope. i.e., you can jump out of a scope but not into a scope.

AnthonyMai
October 17th, 2002, 01:52 PM
Graham said:


Oops, my eyes skipped lines. The wrong statement was made by Paul, not Graham.

jfaust
October 17th, 2002, 01:57 PM
Originally posted by Anthony Mai
you can jump out of a scope but not into a scope


You can jump into a scope just fine:


int main()
{
if( 0 )
{
inner_scope:
return 0;
}

goto inner_scope;
return 1;
}


Jeff

galathaea
October 17th, 2002, 02:00 PM
I did not realize this was the Non Visual c++ forum, so my last post was way off. Coding your own routines in c++ in the style of the termination handler though (all cleanup routines in one exit location) is good style, though, because it allows for easy analysis of completeness. I stand by my "use if needed" statement though, with fists up and ready.

j0nas
October 17th, 2002, 02:14 PM
First I have to say I'm a C programmer, ok :cool:

Graham's talk about RAII doesn't seems to solve all problems... If you define a pointer object and later create an instance of it with the new-operator. How does RAII apply to that and what's the difference between RAII and a good old goto? Goto:s unwind the stack and I guess destructors are called then, or?

It seems that many of you think that it's absolutely wrong to use goto:s.. Black or white, black or white... when the color is gray :p

...Just my view.

AnthonyMai
October 17th, 2002, 02:45 PM
First I rarely find a need for the "goto" statement. I try to not to use it. Also I rarely find the need of having multiple exit points of function calls. And I try to not to have multiple exit point.

But I only follow those rules as rules of thumbs, NOT rules of principle. It is possible, as a principle, that you can absolutely stay away from both goto and multiple exit point, and use alternative ways of achieving what you want. But some times the price of alternative is just too high to be worth it.

If in a specific situation, a goto statement or multiple exit point seems to be an attractive solution, I would NOT hesitate to use them. I do NOT understand arguments of people who tries to tell people "goto" is the mother of all evils.

First. Usage of goto NEVER implies a design flaw. It never implies any thing good or bad of the design. Usage of "goto" is purely an implementation issue. There is NOT a conceiveable design which would mandate usage of goto, and which can not be implemented without goto. I can't think of any thing like that.

Usage of goto has its pros and cons. Whether to use it or not is purely an implementation decision, based on individual's opinion of the balance of pros and cons. Some claim using goto is a bad design. It is never a design issue. Some claim using goto is error prone. Well programmers make all sorts of mistakes. I don't buy it that using goto automatically means your chance of making an error is significantly higher versus when you don't use it.

Show me some statistical data to back it up if you claim goto is more error prone.

Bottom line is: it is possible to stay away from goto completely and absolutely. But it is not necessary to do so. There are both good or bad use of goto. And when it seems to be a good place to use goto, there is no reason why you shouldn't use it.

AnthonyMai
October 17th, 2002, 03:17 PM
... and my point is that you'll waste an awful lot of time looking for a better or more valid example. There aren't any. The set of situations in which the use of goto is elegant, readable, maintainable and correct is vanishingly small.


Graham:
You have to realize that program code that satisfy elegant, readable, maintainable and correct all 4 conditions simply does not exist. So that's not a problem for just goto statement. Most times you have to settle for 3 out of the 4 you meantioned.

Take this computation task as an example: There are 8 short integers a0, a1, ...a7 and 8 other short integers b0, b1,...b7. I want to multiply each a with b (a0 with b0, a1 with b1, etc), divide the result of multiplication by 32768, and sum them up. And I need to make sure the result stays within the range. What's an elegant solution?

Using C/C++ you probably need to write any where from 10 to 20 lines of code and have to do a bunch of "if" to accomplish it. But using some SIMD assembly instruction I can do the whole thing in just one instruction. So who is the elegant?

Here is an example in which the use of goto is not perfect but is surely more elegant than other solutions. You need to do a switch statement in which depending on the switch value, you have to carry out a combination of tasks a0, a1,...an, and one of either b0 or b1 or b2. And the switch has about 100 differeent cases and you want to do it fast, so you really don't want to do it in two different switch statements. What do you do?

I would do this:

switch (val)
{
case 1:
DoTaskA1();
goto TaskB0;
break;
case 2:
DoTaskA2();
goto TaskB0;
break;
case 3:
DoTaskA3();
goto TaskB1;
break;

case 4:
DoTaskA4();
goto TaskB0;
break;

case 99:
DoTaskA99();
Task_B1:
DoTaskB1();
break;

case 100:
DoTaskA100();
Task_B0:
DoTaskB0();
break;

default:
break;
}

PaulWendt
October 17th, 2002, 03:34 PM
Originally posted by AnthonyMai
Paul said:


That's a reasonable imagination of what could happen. But unfortunately it is NOT TRUE. Don't spread the rumor. Check the fact first, Paul!



I think we must have posted at the same time. Right before you
posted this, I made another post modifying the post where I
made the "mistake". What I was talking about in that statement
were non-local gotos [and not the goto keyword]. I should have
made that clear [and I thought I did], but oh well: time to take
my lumps :)

--Paul

PaulWendt
October 17th, 2002, 03:38 PM
Originally posted by j0nas
First I have to say I'm a C programmer, ok :cool:

Graham's talk about RAII doesn't seems to solve all problems... If you define a pointer object and later create an instance of it with the new-operator. How does RAII apply to that and what's the difference between RAII and a good old goto? Goto:s unwind the stack and I guess destructors are called then, or?

It seems that many of you think that it's absolutely wrong to use goto:s.. Black or white, black or white... when the color is gray :p

...Just my view.

A good practice to follow when programming in C++ is to not use
so-called naked pointers like you describe. If you have a pointer
and goto [the keyword] an area where the delete is never
called, you will have a resource leak. If you instead have a class
whose constructor does the new and destructor does the
delete, you won't ever have a resource leak because the
destructor will do the delete when the variable goes out of scope
... whether an exception is thrown or a goto takes you past the
delete or whatever [not the non-local gotos though].

That's the difference.

--Paul

PaulWendt
October 17th, 2002, 03:40 PM
Originally posted by AnthonyMai
First I rarely find a need for the "goto" statement. I try to not to use it. Also I rarely find the need of having multiple exit points of function calls. And I try to not to have multiple exit point.

But I only follow those rules as rules of thumbs, NOT rules of principle. It is possible, as a principle, that you can absolutely stay away from both goto and multiple exit point, and use alternative ways of achieving what you want. But some times the price of alternative is just too high to be worth it.

If in a specific situation, a goto statement or multiple exit point seems to be an attractive solution, I would NOT hesitate to use them. I do NOT understand arguments of people who tries to tell people "goto" is the mother of all evils.

First. Usage of goto NEVER implies a design flaw. It never implies any thing good or bad of the design. Usage of "goto" is purely an implementation issue. There is NOT a conceiveable design which would mandate usage of goto, and which can not be implemented without goto. I can't think of any thing like that.

Usage of goto has its pros and cons. Whether to use it or not is purely an implementation decision, based on individual's opinion of the balance of pros and cons. Some claim using goto is a bad design. It is never a design issue. Some claim using goto is error prone. Well programmers make all sorts of mistakes. I don't buy it that using goto automatically means your chance of making an error is significantly higher versus when you don't use it.

Show me some statistical data to back it up if you claim goto is more error prone.

Bottom line is: it is possible to stay away from goto completely and absolutely. But it is not necessary to do so. There are both good or bad use of goto. And when it seems to be a good place to use goto, there is no reason why you shouldn't use it.

I wholeheartedly agree. This is one of those things that's open
to a wide amount of interpretation by everyone. Each person has
his own ideas regarding what is acceptable use of the goto
keyword. That's another reason why there was a mass exodus
away from the goto keyword in general: when used badly, the
goto keyword CAN create havoc.

--Paul

stober
October 17th, 2002, 06:50 PM
Doesn't your argments in favor the GOTO apply to almost every other contriversial C/C++ statement? For example, some people say never use FILE but use streams instead. Or how about the people who swear by templates in place of macros? Or global/static non-class variables. There are a whole host of these. Use, or non-use, of any of these is not a design flaw but largly the preferences of the coder. I feel more comfortable using FILE instead of streams and my programs reflect that.

And yes, there are some rare occasions to use goto -- I've even seen it once or twice in MFC code.

jfaust
October 17th, 2002, 07:05 PM
It's not merely a preference. It's a maintenance issue. That's primarily why goto's are considered bad. Because it can be difficult to maintain. If you set a breakpoint after a goto flag, it's harder to determine how you got there. It's one thing to imagine a method with a single goto that goes forward. Now imagine a method with three gotos that go forward and back. This becomes very difficult to deal with.

Preferring FILE to streams is a real maintenance issue. Maybe you are certain that your code does not need to be portable or that you'll always have a good portability tool. However good and true this is, it is still an assumption.

Wether it's a good decision or not to use FILE over streams is not really important to this discussion. My point is that there is more to it than "preference." There is a potential cost to it.

Jeff

galathaea
October 17th, 2002, 07:11 PM
I've seen badly nested if's, do/while, and horrendous looking branched recursive function calls. Does this mean that these language features are bad or that they have been used badly?

PaulWendt
October 17th, 2002, 07:16 PM
Originally posted by galathaea
I've seen badly nested if's, do/while, and horrendous looking branched recursive function calls. Does this mean that these language features are bad or that they have been used badly?

In my opinion, it'd mean that the feature was used badly. The
problem with the goto keyword is that it's a lot more flexible
than other commands. Everyone seems to have their own
interpretation on what is "proper" when it comes to the goto
keyword. Because of that, it's hard to quantify whether or not
a particular usage is a poor decision.

galathaea
October 17th, 2002, 07:21 PM
doesn't everyone have their own interpretation on what is proper if/do/while nesting or proper branched recursion style? I've seen several different styles of each. Shouldn't we just say, is this readable and maintainable. Period. Without the taboos.

stober
October 17th, 2002, 07:55 PM
I really miss the setjmp() and longjmp() -- they're like goto but can jump to anywhere within the program, while goto is limited to the function in which it is used. If you have a hard time following a goto, you ought to try figuring out where a longjmp() is going to go!! If there is only one setjmp, then its pretty easy.

AnthonyMai
October 17th, 2002, 08:03 PM
It's not merely a preference. It's a maintenance issue. That's primarily why goto's are considered bad. Because it can be difficult to maintain.


Maintenance issue exists for all language features and I don't see how goto is special. It's all up to how you use it. You can do a wild goto and jump to some place never expected and it's going to be headache. You can throw in 10 different "return" here and there and some resorces never gets cleaned, and it's going to be a headache. If that happens, blame on the person who inproperly used the language feature, not the language feature itself.

goto can be used in a pretty elegant, well structures, and quite maintainable way. It's up to how you use it.


If you set a breakpoint after a goto flag, it's harder to determine how you got there.


Would you be able to figure out how you get there if you set a break point right after a long loop which contains quite a number of different places where "break" is called upon various conditions? You can't either.

As a matter of fact, if you simply replace all the "break" with a "goto" that go to the line right after the loop, chances are the compiled code will look exactly the same and contain the same assembly code.



It's one thing to imagine a method with a single goto that goes forward. Now imagine a method with three gotos that go forward and back. This becomes very difficult to deal with.


If one has a legitimate reason to go backwards. What's wrong with goto backwards? If one does not have a good reason to go backwards, why would one goto backwards just for the sack of goto backwards?

One legitimate use of goto backwards goes like this:

start_calc:
for (i=0; i<1000; i++)
{
for (j=0; j<1000; j++)
{
for (k=0; k<1000; k++)
{
Manipulate Data[i][j][k];

// If some condition raises and we have to re-start
// the calculation again.
if (Something_Goes_Wrong)
{
goto start_calc;
}

// If we have found what we want and there is no need to continue.
if (We_are_all_done_already)
{
goto end_calc;
}
}
}
}
end_calc:


A side note. One language feature that I find totally unacceptable, and causes maintenance problem, is the C++ exceptions.

Exceptions are bad because higher level code never knows who will throw exceptions and from where and under what condition. And the one who throw exceptions never knows who will catch them and where it will be catched and under what circumstance it will be catched. Such uncertainly is the worst enemy in programming.

We see so many uncatched exceptions in day to day code, and even more exceptions caught at wrong places! "Unhandled exceptions" can be accounted for a great portion of all crashing software bugs.

Even worse, C++ exceptions are some sort of contageous decease. A function that does not throw any exceptions at all itself, could be a function that actually throws exception, if amoung the functions it calls, some do throw exception, or if the functions it calls do not catch exceptions from lower level code.
So it is contagenous. And you become an exception throwing function without you even realize it.


Worse of all, no one bothers to catch exceptions. It would be ideal if wheneve you call some exception throwing function (which is basically every thing), you need to wrape the call in a try/catch block. For example when you call new. But no one does it.

Some claim he can "strategically place a few try/catch here and there", and it will catch all exceptions. First that is impossible to do. Second, it is impossible to maintain, since if the code changes, your strategically placed try/catch may need to strategically re-positioned. It is as tough as trying to catch the DC sniper or trying to catch Ben Laden. You simply can not do it with a few dozen or so soldiers "strategically" placed here and there.

Exceptions are evil.

Axter
October 17th, 2002, 09:47 PM
switch (val)
{
case 1:
DoTaskA1();
goto TaskB0;
break;
case 2:
DoTaskA2();
goto TaskB0;
break;
case 3:
DoTaskA3();
goto TaskB1;
break;

case 4:
DoTaskA4();
goto TaskB0;
break;

case 99:
DoTaskA99();
Task_B1:
DoTaskB1();
break;

case 100:
DoTaskA100();
Task_B0:
DoTaskB0();
break;

default:
break;
}


No offence, but the above code is a poor execuse for justifying a goto statement.

You can easily accomplish the samething by adding another switch statement, and the code would look more readable, and be easier to follow.

Example

int main(int argc, char* argv[])
{
int SecondTask = 0;
enum {Task_B0 = 1, Task_B1 = 2};
switch (argc)
{
case 1:
DoTaskA1();
SecondTask = Task_B0;
break;
case 2:
DoTaskA2();
SecondTask = Task_B0;
break;
case 3:
DoTaskA3();
SecondTask = Task_B1;
break;
case 4:
DoTaskA4();
SecondTask = Task_B0;
break;
case 99:
DoTaskA99();
SecondTask = Task_B1;
DoTaskB1();
break;

case 100:
DoTaskA100();
SecondTask = Task_B0;
break;

default:
break;
}

switch(SecondTask)
{
case Task_B1:
DoTaskB1();
break;
case Task_B0:
DoTaskB0();
break;
}

return 0;
}


I can find absolutely no excuse for needing a goto statement.
I've been programming in C/C++ since 1987.
In my first year of programming, when I didn't know any better, I did use goto's. The fact that my first language was BASIC, may it that much more tempting to use goto’s.

Since my second year of programming in C/C++ (1988) I have not found a single situation in which I had to use a goto statement.

I have not run into any condition in which I thought, “Wow! …. A goto statement would work so much better here!”

The use of goto’s too often results in spaghetti code, that is hard to read, and hard to maintain.
My advice is NEVER, NEVER, NEVER use a goto statement….. There always a better non-goto method to accomplish the same thing or better.

It’s not required for C/C++ programming, and your code will be easier to follow and easier to maintain without it.

Graham
October 18th, 2002, 04:06 AM
Originally posted by Axter
I have not run into any condition in which I thought, “Wow! …. A goto statement would work so much better here!”

The use of goto’s too often results in spaghetti code, that is hard to read, and hard to maintain.
My advice is NEVER, NEVER, NEVER use a goto statement….. There always a better non-goto method to accomplish the same thing or better.

It’s not required for C/C++ programming, and your code will be easier to follow and easier to maintain without it. Absolutely agree.

(Slightly OT, but...) Was there ever a greater abomination in a coding language than VB's "On Error GoTo"? On those occasions when I have to debug VB code, I break out into a cold sweat whenever I see that, because I just know that I'm going to find myself suddenly warping to a different place in the source with only a vague idea of where I came from.

AnthonyMai
October 18th, 2002, 09:10 AM
Can any one dispute the legitimate use where you use a GOTO to break out of several nested loops. It is definitely more concise and more readable than using multiple "break"s to achieve the goal.

In principle, there is nothing that must be accomplished using goto and can't have an alternative solution. In practice, in some situations, goto is more concise, more readable, and one would be more attempted to use goto than an alternative solution.

Using good judgements and try to avoid goto where possible, but use it where it seems to be better, is one thing. Observe the abstence of goto like the eleventh commandment and swear to never ever use it, that's another thing. That's not rational. That's religious.

It's like alcohol. There are much more bad things than good things in alcohol. Drunken drivers being one, amoung other things. In principle, one can live without alcohol. In practice, it is good to try to avoid aocohol as much as possible, but DO drink it when the occasion is appropriate. If you observe the absolute abstence of alcohol, then you have become religious.

You can try to convince me in each and every specific situations, it's better NOT to drink alcohol rather than drink it. But if you are trying to convince people to observe the absolute abstence of alcohol under all situations, then that is just too much.

Yves M
October 18th, 2002, 09:19 AM
I never use goto and actually never use break or continue. But then again, I can see advantages of using it. Maybe Antony's example isn't compelling, although it's not easier or harder to read than Axter's change IMHO.

Programmers who write a lot of C-style code mixed with assembler code might prefer to use gotos. This would lend itself to situations where you have a few asm blocks inside a function, but don't want to code the whole function in asm. I can see nothing majorly wrong there, since using asm usually involves jumps anyways.

On a side note, the VB On Error Goto statement can be helpful for automatically debugging your application. It is also essential for working with COM objects since VB just throws an error if the HRESULT is not S_OK. But well, VB isn't the nicest programming language anyways ;)

Axter
October 18th, 2002, 09:25 AM
for (int x = 0;x < 100;++x)
{
bool BreakOutOf_X_loop = false;
for(int y = 0;y < 10;++y)
{
if (y == 5 && x == 10)
{
BreakOutOf_X_loop = true;
break;
}
}
if (BreakOutOf_X_loop) break;
}


IMHO, the above code reads and functions much better using an extra well defined bool variable then using a goto statement.
It's easier to maintain and the logic is easy to follow.

As I stated before, a goto statement is never needed.
If you or any one else which to use it in your code, that is your choice.
Just as it is my choice to call it as I see it. And as I see it, a goto is never, never, never needed.

Yves M
October 18th, 2002, 09:38 AM
Well, I prefer using while loops when execution can break inside a loop. This makes it clear that the loop is not always executed a fixed number of times (that's what a for loop means to me).

But then again I programmed in Pascal for a long time before coming to C/C++ ;)


bool BreakLoop = false;
x = 0;
while ((x < 100) && !BreakLoop)
{
y = 0;
while ((y < 10) && !BreakLoop)
{
if (y == 5 && x == 10)
{
BreakLoop = true;
}
++y;
}
++x;
}

galathaea
October 18th, 2002, 11:23 AM
Here is the real issue. So, someone working for me submits the following code flow:


// inside somewhere

// some code
if (//some condition) goto here;

// some more code

here:
// some more code


and someone else working for me submits:


// inside somewhere

// some code
if (//not some condition)
{
// some more code
}

// some more code here


I look at both of them. I understand both of them. I can maintain both of them. So I give both of them paychecks and we all go home happy. Now my challenge. Is there ANY coding issue with the goto that is being missed? I don't want to know if it can be done differently, since I can think of hundreds of ways. What I am asking is: is there any development issues, actual problems that could come down the line, that can be fixed up with the if but REQUIRES removal of the goto or more work with the goto. Because I have this sneaky suspicion that the only reason people dislike the goto is because "someone greater then thee" has shown disdain at its use, and for no real coding issue.

Really, the while keyword can be looked at as unnecessary. Since I can always do a while with an if/goto combination. Does this really mean I should never, never, never use a while? Or are we really so c++ illiterate that we cannot understand looking at a goto what it does but we can understand a while and some of the more "common folk" tongue. I have no problems with readability, etc.

Side note: exception handling is DEFINITELY necessary in some places. Say I am writing an API interception and am performing my interception in some process in a galaxy far away. I get a list of currently loaded modules and begin patching their IAT. But that process is doing its own thing, and one of the modules I am patching is unloaded while writing the thunks. Do I let my interception crash the process, or do I catch the memory exception that is going to occur and use it to have my program realize that that module is no longer there and I should move on to the next?

stober
October 18th, 2002, 11:38 AM
Here is a real-life example from MFC COleDateTime class. Note that it would be extremly difficult to code this without the goto.


static BOOL _TmFromOleDate(DATE dtSrc, struct tm& tmDest)
{
// The legal range does not actually span year 0 to 9999.
if (dtSrc > MAX_DATE || dtSrc < MIN_DATE) // about year 100 to about 9999
return FALSE;

long nDays; // Number of days since Dec. 30, 1899
long nDaysAbsolute; // Number of days since 1/1/0
long nSecsInDay; // Time in seconds since midnight
long nMinutesInDay; // Minutes in day

long n400Years; // Number of 400 year increments since 1/1/0
long n400Century; // Century within 400 year block (0,1,2 or 3)
long n4Years; // Number of 4 year increments since 1/1/0
long n4Day; // Day within 4 year block
// (0 is 1/1/yr1, 1460 is 12/31/yr4)
long n4Yr; // Year within 4 year block (0,1,2 or 3)
BOOL bLeap4 = TRUE; // TRUE if 4 year block includes leap year

double dblDate = dtSrc; // tempory serial date

// If a valid date, then this conversion should not overflow
nDays = (long)dblDate;

// Round to the second
// dblDate += ((dtSrc > 0.0) ? HALF_SECOND : -HALF_SECOND);

nDaysAbsolute = (long)dblDate + 693959L; // Add days from 1/1/0 to 12/30/1899

dblDate = fabs(dblDate);
double dblTimePart = dblDate - floor(dblDate);
double dblSecsInDay = dblTimePart * 86400.0F;
nSecsInDay = (long)(dblSecsInDay);

double deltaSecs = dblSecsInDay - (double)nSecsInDay; // milliseconds
if(deltaSecs > 0.999000F)
nSecsInDay++;

// Calculate the day of week (sun=1, mon=2...)
// -1 because 1/1/0 is Sat. +1 because we want 1-based
tmDest.tm_wday = (int)((nDaysAbsolute - 1) % 7L) + 1;

// Leap years every 4 yrs except centuries not multiples of 400.
n400Years = (long)(nDaysAbsolute / 146097L);

// Set nDaysAbsolute to day within 400-year block
nDaysAbsolute %= 146097L;

// -1 because first century has extra day
n400Century = (long)((nDaysAbsolute - 1) / 36524L);

// Non-leap century
if (n400Century != 0)
{
// Set nDaysAbsolute to day within century
nDaysAbsolute = (nDaysAbsolute - 1) % 36524L;

// +1 because 1st 4 year increment has 1460 days
n4Years = (long)((nDaysAbsolute + 1) / 1461L);

if (n4Years != 0)
n4Day = (long)((nDaysAbsolute + 1) % 1461L);
else
{
bLeap4 = FALSE;
n4Day = (long)nDaysAbsolute;
}
}
else
{
// Leap century - not special case!
n4Years = (long)(nDaysAbsolute / 1461L);
n4Day = (long)(nDaysAbsolute % 1461L);
}

if (bLeap4)
{
// -1 because first year has 366 days
n4Yr = (n4Day - 1) / 365;

if (n4Yr != 0)
n4Day = (n4Day - 1) % 365;
}
else
{
n4Yr = n4Day / 365;
n4Day %= 365;
}

// n4Day is now 0-based day of year. Save 1-based day of year, year number
tmDest.tm_yday = (int)n4Day + 1;
tmDest.tm_year = n400Years * 400 + n400Century * 100 + n4Years * 4 + n4Yr;

// Handle leap year: before, on, and after Feb. 29.
if (n4Yr == 0 && bLeap4)
{
// Leap Year
if (n4Day == 59)
{
/* Feb. 29 */
tmDest.tm_mon = 2;
tmDest.tm_mday = 29;
goto DoTime;
}

// Pretend it's not a leap year for month/day comp.
if (n4Day >= 60)
--n4Day;
}

// Make n4DaY a 1-based day of non-leap year and compute
// month/day for everything but Feb. 29.
++n4Day;

// Month number always >= n/32, so save some loop time */
for (tmDest.tm_mon = (n4Day >> 5) + 1;
n4Day > _afxMonthDays[tmDest.tm_mon]; tmDest.tm_mon++);

tmDest.tm_mday = (int)(n4Day - _afxMonthDays[tmDest.tm_mon-1]);

DoTime:
if (nSecsInDay == 0)
tmDest.tm_hour = tmDest.tm_min = tmDest.tm_sec = 0;
else
{
tmDest.tm_sec = (int)nSecsInDay % 60L;
nMinutesInDay = nSecsInDay / 60L;
tmDest.tm_min = (int)nMinutesInDay % 60;
tmDest.tm_hour = (int)nMinutesInDay / 60;
}

return TRUE;
}

jfaust
October 18th, 2002, 11:54 AM
The danger of goto is simply that it can be easily abused, and in the past was often abused. This past abuse was largely corrected with an attitude change

It's partly because of the current attitude towards goto that you won't find it abused as it once was. Since goto does not solve any problems that cannot be solved otherwise, I'd rather maintain this attitude.

The logical flow of a method is more easily be muddled with goto. It's non-continuous. It jumps.

Used prudently, with care, goto will not cause a serious maintenance problem. But, because of the ease with which it can be abused, I still feel it is best to not use.

Jeff

galathaea
October 18th, 2002, 12:09 PM
Pointers can be easily abused. And as I said above, while doesn't solve any problems that can't be solved otherwise. And there are MANY keywords that jump. If your reasons apply to other keywords besides goto, I see them as invalid. Give me REAL reasons.

** galathaea gives that cheese-western squint **
"Come on space cowboys..."

PaulWendt
October 18th, 2002, 12:14 PM
Originally posted by galathaea
Pointers can be easily abused. And as I said above, while doesn't solve any problems that can't be solved otherwise. And there are MANY keywords that jump. If your reasons apply to other keywords besides goto, I see them as invalid. Give me REAL reasons.

** galathaea gives that cheese-western squint **
"Come on space cowboys..."

What keywords jump? The only I can think of off the top of my
head would be the switch/case constructs, break, and continue.
continue and break do jump, but their jumping is a lot more
limited. Even so, plenty of people have made the mistake where
they forget to put a break in one of their case: areas of a
switch statement. The jumping statements can be misused or
create problems down the road. The thing is that continue/break/
switch/case all are a lot more limited with respect to where they
can jump. Their jumping is a lot more structured than goto's
jump. It's because of goto's flexibility that it can be misused.

So ... yeah, the same problem can exist with all jumping
keywords, but goto is significantly different than these other
keywords so in my opinion, the problem is exacerbated.

--Paul

jfaust
October 18th, 2002, 12:23 PM
Real reasons what? There's no reason you can't use goto. It can lead to bad code when used incorrectly. So can other things. The thing with goto was that it was often used incorrectly, leading to remarkably difficult code to maintain.

This misuse was so common that a now well-known paper was written by Dijkstra as to why it was harmful. You've probably heard his name before.

This paper had a tremendous effect on the programming community. This paper is now considered by some to be a little extreme, but coming from the standpoint of 1968, I think his disdain is well placed.

This paper is largely responsible for current attitudes toward goto. Here is a link: http://www.acm.org/classics/oct95/

He sums up my standpoint entirely in "it is too much an invitation to make a mess of one's program".

Jeff

galathaea
October 18th, 2002, 12:24 PM
Ifs don't jump? While's don't jump? For's don't jump? I think your definition of jump is not valid since all the things I just mentioned compile to different jumps. Is the problem that you don't know where a goto jumps to but the others you can figure out? Then that sounds like a problem understanding the language. Is the problem that goto is flexible? Is that really a minus? Yes, keywords can be abused to unrecognizability. Just check out the International Obfuscated C Code contest. Mains can be arrays instead of functions. I still think this may be a problem with timid programmers folllowing unsubstantiated "guru" advice instead of independent thinking, and not a REAL issue...

** galathaea gives that cheese-western squint **
"Come on space cowboys..."

Philip Nicoletti
October 18th, 2002, 12:44 PM
previously posted by galathaea


// inside somewhere

// some code
if (//some condition) goto here;

// some more code

here:
// some more code





hmmmmmmm ... try to compile ...


// inside somewhere

// some code
if (//some condition) goto here;

// some more code
std::vector<int> v(1000000);
int i = 10;

here:
// some more code




Forget some brackets ? Easy to do using goto when they were not
needed originally, but something is added later that requires
putting them in.

galathaea
October 18th, 2002, 12:52 PM
There is a design principle that I follow that goes like this: always declare local variables at the head of their locality. If you need to create a new locality with new variable declarations, that is simple in c++. Yes, not following good design is a problem. But such a mistake is not a goto problem. It is a design problem. If you have bad design, you have bad design with or without the goto.

** galathaeapistolero blows smoke from the barrel **
"Next space cowboy?"

PaulWendt
October 18th, 2002, 12:54 PM
Originally posted by galathaea
Ifs don't jump? While's don't jump? For's don't jump? I think your definition of jump is not valid since all the things I just mentioned compile to different jumps. Is the problem that you don't know where a goto jumps to but the others you can figure out? Then that sounds like a problem understanding the language. Is the problem that goto is flexible? Is that really a minus? Yes, keywords can be abused to unrecognizability. Just check out the International Obfuscated C Code contest. Mains can be arrays instead of functions. I still think this may be a problem with timid programmers folllowing unsubstantiated "guru" advice instead of independent thinking, and not a REAL issue...

** galathaea gives that cheese-western squint **
"Come on space cowboys..."

I don't have the fundamental misunderstandings that you are
implying. I can't give you a 1-to-1 correlation between C++
keywords and assembly statements, but I realize that if's are
broken down to low-level assembly routines that, of course, jump.
The thing is that an if is very structured; a while is very
structured. A goto ... well it's a lot more low-level. I am not
saying that that low-leveledness is a bad thing, either. I can
think of some times where I'd prefer to use a goto even though
there are other alternatives [like nested loops]. Like jfaust was
saying earlier, the thing with goto is that everyone has their
own opinion with respect to what "proper" usage of the goto
keyword is. Since goto is so low-level, its use should be
considered carefully. Because it's so flexible, I choose to be
careful with it. I, for one, never advocated NOT using it. I don't
use it often, however, and I tend to find the benefits of using it
minor compared to the potential headaches that can arise
through its use.

--Paul

jfaust
October 18th, 2002, 12:58 PM
It is a design problem.


As correctly stated by Anthony Mai, it is not a design problem. It is an implementation detail. As correctly demonstrated by Philip Nicoletti, goto can be more error prone.

Jeff

galathaea
October 18th, 2002, 01:04 PM
switch (//some switch variable)
{
case //case1:
std::vector<int> v(1000000);
int i = 10;
break;
// next cases
}


forget some brackets?

Philip Nicoletti
October 18th, 2002, 01:14 PM
previously posted by galathaea ...

switch (//some switch variable)
{
case //case1:
std::vector<int> v(1000000);
int i = 10;
break;
// next cases
}
--------------------------------------------------------------------------------


forget some brackets?


Nope ... I did not post that code.

Plus you were asking why


if (something) goto here
//
//
here:


is not as good as


if (something)
{
//
//
}

galathaea
October 18th, 2002, 01:21 PM
re: Phillip Nicolleti

No, but that same wiley programmer who didn't follow a good design suggestion added those variables to a switch statement like they did to my goto. You have to see how this invalidates your argument against goto being the culprit? Don't you?

Re: jfaust

Don't you?

Philip Nicoletti
October 18th, 2002, 01:24 PM
not at all, I edited my previous post, but you
replied to fast for me ...

You were comparing the merits of two particular
constructs. That's what I did.

Philip Nicoletti
October 18th, 2002, 01:43 PM
Sorry for the multiple posts here, I probably should
think of everything I want to say and put it all in one
post, but ...

By the way, if you look, I never said that I was against
the use of goto in all circumstances. I said I was against
it in the case that galathaea mentioned.

For the record : I started programming in Fortran 66,
where you HAD to use goto, computed gotos,
arithmetic if, and the like. With Fortran 77, and then
Fortran 9x, the need for these constructs is minimal.
Although I have no "religious type" of belief against
the use of goto, I probably have not used one in
over 10 years - simply because I never saw the need.
(and I still do 75 percent of my programming in Fortran).


Also, Stroustrup mentions that one valid use of goto
is to break out of inner-loops in nested loops.

galathaea
October 18th, 2002, 02:15 PM
I do understand your point Phillip, and I'm not assuming that you ever said goto's were bad. But there are still people who would never, never, never use goto and feel some kind of animosity towards its use, and I am just trying to defend this lonely keyword. It has been abused and neglected for too long, and it wasn't born evil. It can't defend itself.

The code I posted first comparing goto and a block statement I still defend. Its a perfectly legitimate use. My example with the switch was to show that the reason you do not like the use of goto in that place is due to someone creating a problem because of bad design. It does not exist because of the goto. Design principles are created precisely because a consistent design should not allow unexpected errors such as the one you posted. Note how the design principle I stated was general to the problem of variable locality and had nothing to do with an exceptional situation that arises because of goto.

The Stroustrup example you give is a good use of goto as well, but it has the advantage of being a simpler solution than variable testing in each loop. This is the exemplar of goto programming, but I did not want to give goto an advantage. I'm trying to show how even casual use of goto is not something to check over your shoulder for, as long as you are still respecting good design principles. Any good, consistent design principles that follows the good design principles = avoids potential errors in coding equation should allow even the use of gotos in proper circumstances.

So I still believe that the previous comparison post of goto v. blocks is valid and that the "problem" that Phillip mentions is not a problem that should be given to goto. Remember, I didn't post the code with variables either.

jfaust
October 18th, 2002, 02:35 PM
Re: jfaust
Don't you?


goto is a flow of control language feature. No other flow of control keyword has caused so much problems as goto. I've debugged code written in the 60s. I still have nightmares.

When I look at any problem I first look at it from a maintenance standpoint. Just because you know the issues well enough and are intelligent enough doesn't mean the next guy modifying your code will be.

goto is a simple concept that can lead to complex bugs. This discrepency is the heart of why it can be dangerous.

I quoted Dijkstra previously, "it is too much an invitation to make a mess of one's program". Maybe you won't make a mess of it, but the next guy very well could.

Jeff

mdangers
October 18th, 2002, 02:52 PM
Side note: exception handling is DEFINITELY necessary in some places. Say I am writing an API interception and am performing my interception in some process in a galaxy far away. I get a list of currently loaded modules and begin patching their IAT. But that process is doing its own thing, and one of the modules I am patching is unloaded while writing the thunks. Do I let my interception crash the process, or do I catch the memory exception that is going to occur and use it to have my program realize that that module is no longer there and I should move on to the next?



Wasn't the subject 'C++ exceptions' ?

Sounds more like SEH to me.

galathaea
October 18th, 2002, 03:10 PM
My senior project in college was to update some code written in Fortran77 to simulate the recombination of antiprotons and positrons in the formation of AntiHydrogen. I needed to update the recombination algorithms to reflect current theory and optimize performance. It was horrible. I basically had to rewrite the entire program, and some of the problems were goto related. But I never blamed goto. I blamed the design principles (or lack of) of the original coder. The goto type statements were easy targets early on, because solid design principles were not formulated early on in programming language theory. And in place of general design principles, earlier principles tended to focus on linguistic characteristics of specific keywords. But we have evolved since then. Now design principles concentrate on logic flow, type principles, and general development consistency issues focused on the entire product path. I do not think it is legitamate or even good practice to substitue archaic practices for modern design principles. As our knowledge increases, we should replace old prejudices which, as I had surmised above, come from "gurus" of the past. I try not to hire those who lack understanding of good design principles, so that these wiley programmers won't be able to "maintain" my code in horrendous ways. Ways, I should add, that my previous posts show are not in any way to blame on goto.

jflegert
October 18th, 2002, 03:14 PM
Originally posted by galathaea
Here is the real issue. So, someone working for me submits the following code flow:


// inside somewhere

// some code
if (//some condition) goto here;

// some more code

here:
// some more code


and someone else working for me submits:


// inside somewhere

// some code
if (//not some condition)
{
// some more code
}

// some more code here


I look at both of them. I understand both of them. I can maintain both of them.
...


I don't think you can use such a simple example. When maintaining code, I would hate to see a goto used instead of a "then" block as a "standard" coding practice. If there were ten if statements in a block of code, you would have to make sure that each goto matched up with its appropriate tag (and come up with ten tag names). This sounds like a headache and a likely cause of errors.

Also what would you propose if there was an "else" block?

For "if" statements, bracketed "then" blocks appears to be the defacto standard for coding. Why does one person need to use the goto? I think you should enforce some standards. :)

Regards,
John Flegert

galathaea
October 18th, 2002, 03:37 PM
I was not using the goto as a generic then block, but I have little qualms over its use in this way. The main problem would be pollution of label name space, but even that is little concern these days if you have a good naming convention. I was mainly using goto as a general program flow redirector, which could be done with while, if, switch, and others. I was trying to show that flow decisions can be accomplished with goto without there being anything scary going on. All of the multiple if/else problems you mention could be coded with switches just as easily, but I don't want to enforce if/else or switch unless there are optimization concerns. (Yes I do understand the compiled ML differences of these as well).


I think you should enforce some standards.


I have no problems with any linguistic styles a coder uses if they follow good design principles. This includes placement of {}, indentation styles, and yes, even the choice of goto v. other flow control. Consistency is as much an issue here as it is with reading novels. You get "into" them by becoming familiar with an author's style and understanding their intent. I do not want to become a code fashion police officer in my company, as that has always seemed to me tantamount to release of my duty to be able to read code. Reading code, in any style, is the first thing one should learn how to do.


This sounds like a headache and a likely cause of errors.


What errors that are not design related (as opposed to the implied goto related)? This was my question. All the errors people keep referring apply to the switch case and others as well, and I have tried to show that this is a design problem unrelated to poor goto. I enforce design, not fashion.

AnthonyMai
October 18th, 2002, 05:13 PM
Side note: exception handling is DEFINITELY necessary in some places. Say I am writing an API interception and am performing my interception in some process in a galaxy far away. I get a list of currently loaded modules and begin patching their IAT. But that process is doing its own thing, and one of the modules I am patching is unloaded while writing the thunks. Do I let my interception crash the process, or do I catch the memory exception that is going to occur and use it to have my program realize that that module is no longer there and I should move on to the next?


I am talking about C++ exception (those created by a "throw" C++ statement), and you are talking about OS exceptions (Generated by the OS because you are accessing invalid memory or try to divide by zero, or executing a none-exist CPU instruction)

These are totally different things. OS exceptions are completely unpredictable and your code can do very little about it, nor can you prevent it from happening. But for C++ exception, you are in total control, you have the option to NOT to throw an exception and instead return an error code.

By throwing a C++ exception, you are basically placing a wild "goto" statement, with the whereabout it may end up totally unpredictable and unmanageable. Nothing can be worse.

There are things in a program's life that it simply can not predict and can not handle, like the power cord is suddenly pulled out. But for those things predictable and manageable, it should try to handle things in a nice way and recover from error in a graceful way. Simply throwing an exception and hope some god speed piece of code may catch it is just irresponsible.

Back to your presumed situation, if a process is using a module, then the module should not be unloaded. If it is unloaded, then it is either the OS or some one else's bug, and it is not something you can handle, and so handle it not you should.

galathaea
October 18th, 2002, 05:18 PM
Quick off topic: the c++ catch(...) will catch access violations. Which exception is thrown I do not fully understand, since it is a machine dependent exception, and I don't think that there is an ANSI standard exception type for it. But it will be caught (I had to test this once, because I did not know). When I code something like I mentioned, though, I use SEH, because it is the only way I know of to get better information. We could start a new thread if anyone wants to discuss this more and enlighten me.

galathaea
October 18th, 2002, 05:20 PM
Still off topic: No. FreeLibrary is not a programming error. Remember, in API interception, these are other peoples processes.

mdangers
October 18th, 2002, 05:40 PM
We could start a new thread if anyone wants to discuss this more and enlighten me.


I'd like a discussion about the stuff I quoted from your post in my previous one.

I don't think I could contribute much to this, though I would like to. The few things I know are just from stuff that I read, nothing I experienced myself.

If you could point me to (web-)resources on the subject, i'd really appreciate it.

Axter
October 18th, 2002, 06:14 PM
Here is a real-life example from MFC COleDateTime class. Note that it would be extremly difficult to code this without the goto.

Oh come on..... You have to be kidding me......

That example is so easy to do without a goto. It doesn't take much effort at all to modify that example to do the exact same thing without the goto.

Example:

static BOOL _TmFromOleDate(DATE dtSrc, struct tm& tmDest)
{
// The legal range does not actually span year 0 to 9999.
if (dtSrc > MAX_DATE || dtSrc < MIN_DATE) // about year 100 to about 9999
return FALSE;

long nDays; // Number of days since Dec. 30, 1899
long nDaysAbsolute; // Number of days since 1/1/0
long nSecsInDay; // Time in seconds since midnight
long nMinutesInDay; // Minutes in day

long n400Years; // Number of 400 year increments since 1/1/0
long n400Century; // Century within 400 year block (0,1,2 or 3)
long n4Years; // Number of 4 year increments since 1/1/0
long n4Day; // Day within 4 year block
// (0 is 1/1/yr1, 1460 is 12/31/yr4)
long n4Yr; // Year within 4 year block (0,1,2 or 3)
BOOL bLeap4 = TRUE; // TRUE if 4 year block includes leap year

double dblDate = dtSrc; // tempory serial date

// If a valid date, then this conversion should not overflow
nDays = (long)dblDate;

// Round to the second
// dblDate += ((dtSrc > 0.0) ? HALF_SECOND : -HALF_SECOND);

nDaysAbsolute = (long)dblDate + 693959L; // Add days from 1/1/0 to 12/30/1899

dblDate = fabs(dblDate);
double dblTimePart = dblDate - floor(dblDate);
double dblSecsInDay = dblTimePart * 86400.0F;
nSecsInDay = (long)(dblSecsInDay);

double deltaSecs = dblSecsInDay - (double)nSecsInDay; // milliseconds
if(deltaSecs > 0.999000F)
nSecsInDay++;

// Calculate the day of week (sun=1, mon=2...)
// -1 because 1/1/0 is Sat. +1 because we want 1-based
tmDest.tm_wday = (int)((nDaysAbsolute - 1) % 7L) + 1;

// Leap years every 4 yrs except centuries not multiples of 400.
n400Years = (long)(nDaysAbsolute / 146097L);

// Set nDaysAbsolute to day within 400-year block
nDaysAbsolute %= 146097L;

// -1 because first century has extra day
n400Century = (long)((nDaysAbsolute - 1) / 36524L);

// Non-leap century
if (n400Century != 0)
{
// Set nDaysAbsolute to day within century
nDaysAbsolute = (nDaysAbsolute - 1) % 36524L;

// +1 because 1st 4 year increment has 1460 days
n4Years = (long)((nDaysAbsolute + 1) / 1461L);

if (n4Years != 0)
n4Day = (long)((nDaysAbsolute + 1) % 1461L);
else
{
bLeap4 = FALSE;
n4Day = (long)nDaysAbsolute;
}
}
else
{
// Leap century - not special case!
n4Years = (long)(nDaysAbsolute / 1461L);
n4Day = (long)(nDaysAbsolute % 1461L);
}

if (bLeap4)
{
// -1 because first year has 366 days
n4Yr = (n4Day - 1) / 365;

if (n4Yr != 0)
n4Day = (n4Day - 1) % 365;
}
else
{
n4Yr = n4Day / 365;
n4Day %= 365;
}

// n4Day is now 0-based day of year. Save 1-based day of year, year number
tmDest.tm_yday = (int)n4Day + 1;
tmDest.tm_year = n400Years * 400 + n400Century * 100 + n4Years * 4 + n4Yr;

for(;;)//end less loop
{
// Handle leap year: before, on, and after Feb. 29.
if (n4Yr == 0 && bLeap4)
{
// Leap Year
if (n4Day == 59)
{
/* Feb. 29 */
tmDest.tm_mon = 2;
tmDest.tm_mday = 29;
break; //goto DoTime;
}

// Pretend it's not a leap year for month/day comp.
if (n4Day >= 60)
--n4Day;
}

// Make n4DaY a 1-based day of non-leap year and compute
// month/day for everything but Feb. 29.
++n4Day;

// Month number always >= n/32, so save some loop time */
for (tmDest.tm_mon = (n4Day >> 5) + 1;
n4Day > _afxMonthDays[tmDest.tm_mon]; tmDest.tm_mon++);

tmDest.tm_mday = (int)(n4Day - _afxMonthDays[tmDest.tm_mon-1]);
break;
}

//DoTime: Not needed
if (nSecsInDay == 0)
tmDest.tm_hour = tmDest.tm_min = tmDest.tm_sec = 0;
else
{
tmDest.tm_sec = (int)nSecsInDay % 60L;
nMinutesInDay = nSecsInDay / 60L;
tmDest.tm_min = (int)nMinutesInDay % 60;
tmDest.tm_hour = (int)nMinutesInDay / 60;
}

return TRUE;
}


For those who say they need goto for the purpose of a clean-up section, you can easily use the above method instead of a goto.

Second Example:

std::string foofoo(void)
{
std::string ReturnValue;
for(;;)//end less loop
{
//Put your main function code here
//Use break to exit and get to your cleanup section
//End of your main function code
break;
}
//Do clean up here
return ReturnValue;
}


Yet another execuse for goto put to rest.

There's absolutely no need for a goto.
For every example you can post for a need for a goto, any moderate C++ expert can post a replacement method that can do the same without the goto.

Axter
October 18th, 2002, 06:18 PM
Ok, that last post didn't come out right. Let me see if I can repost without the stupid smily face.


std::string foofoo(void)
{
std::string ReturnValue;
for( ; ; )//end less loop
{
//Put your main function code here
//Use break to exit and get to your cleanup section
//End of your main function code
break;
}
//Do clean up here
return ReturnValue;
}

galathaea
October 18th, 2002, 06:22 PM
You have missed the point. Anything that can be done with a while, switch, if, for can be done with a goto. Just because a keyword is unnecessary does not mean it should leave the language.

jflegert
October 21st, 2002, 07:31 AM
Originally posted by galathaea
I was not using the goto as a generic then block, but I have little qualms over its use in this way. The main problem would be pollution of label name space, but even that is little concern these days if you have a good naming convention. ...


Unless there is ONLY one person (and that person is NEVER going to change) who will ever maintain the code, I disagree.

I would think you would strongly encourge your programmers to agree on a standard, and whatever they did agree on, I would guess it wouldn't be what you posted in your example.

Regards,
John Flegert

jflegert
October 21st, 2002, 07:34 AM
As an addition, look in this forum. There is currently a topic asking for comments about if, then, else. I don't see anyone suggesting using goto.

galathaea
October 21st, 2002, 11:22 AM
I am trying to show that all of the fears of goto are fears of bad design principles. If you agree on a particular set of design principles, then you can use any keywords you feel comfortable with and not confuse any future development. I still don't feel that any of the comments against the use of goto have had anything to do with the problems goto may present to a development cycle. They have all seemed to me to be bad design principles in general. It is my position that the ONLY thing that a development group should have to agree on is their design principles. This is the classic linguistic argument against word-related syntax being the focus of a linguistic debate and the argument for a complete grammar related debate on form.

jfaust
October 21st, 2002, 11:32 AM
I am trying to show that all of the fears of goto are fears of bad design principles.


Again, goto has nothing to do with design. Absolutely nothing. It is an implementation detail and a maintenance nightmare, but in no way is it a design issue.

History has shown goto to be bad. If you so happen to think we're smarter now than in the past, go ahead and use it. Please, use it. It may very well be the only way to prove us right.

There is no implementation reason not to use it. It directly causes no runtime problems. All the problems it causes are maintenance related. You ask for implementation reasons not to use it. Well, there are none. That does not mean it should be used.

Jeff

galathaea
October 21st, 2002, 11:41 AM
Again, goto has nothing to do with design. Absolutely nothing. It is an implementation detail and a maintenance nightmare, but in no way is it a design issue.


But all of the reasons against using goto seem to be based on the use of bad design. What I have been saying is that the implementation of a branching structure is never a problem if one is following good design principles. I do understand the difference between design and implementation. It is precisely the linguistic differentiation that I have been making! If you are using a good set of design principles, I have been arguing that the implementation is immaterial to "goodness" or "badness" of maintainability. This was the reason for the shift of computer language theory from keyword-based syntax of the 50s and 60s to a form-based analysis of grammars in the Object Oriented generation.

jfaust
October 21st, 2002, 11:47 AM
the implementation is immaterial to "goodness" or "badness" of maintainability.


Implementation is crucial to maintainability. Software changes. Not matter how well it's designed, there is always a bit of evolution involved. It grows and changes. Bugs are fixed, features are added. That method you wrote 10 years ago, the one with the goto in it, may have gone through many modifications. Software is not something you write well once and leave sit. That's a nice thought, but it doesn't work that way. If it was so, then the use of goto would hardly be an issue. But it's is not so, and it is an issue.

Jeff

galathaea
October 21st, 2002, 12:37 PM
Are there any problems with maintainability of a goto statement when the code is updated in a manner that follows good design principles? The design principles that I think are most relevant are:

Variables (in any language) should be declared/initialized at the start of the code block in which they are used (a "Declared Use" idiom).
Code blocks (in any language) should be as atomic as possible (an "Encapsulation" idiom).
A naming convention for all identifier types should be agreed upon by the developers before production (a "Namespace Maintenance" idiom).
The execution flow of a code block should follow in its reading the originally designed flow for the functionality desired (a "Flow Maintenance" idiom).


The point is that I do understand that the implementation will change as development progresses over the products lifetime. But, as long as design principles are followed, the implementation should never affect maintainability. This was the reason for the switch in linguistic research to form in the first place, ie. to provide for keyword independent rules that allow the creation of useable and maintainable code. If goto is an exception, then it is important to find out why because this would invalidate the current state of this line of research.

I am glad this thread is pursuing these issues, because it is very important to the entire field of general design principles, and I hope there will be more posting from all of those who have an interest in expanding this field.

So I will repeat my question. Are there any problems with maintainability of a goto statement when the code is updated in a manner that follows good design principles?

Philip Nicoletti
October 21st, 2002, 12:54 PM
galathaea,

You mentioned 4 design principles above.

Let's look at your "if (...) goto here; ... here:" vs
the standard "if(...){}" syntax.

using if (...) goto here; ... here:"


you can not even declare std::vector to be used inside the block.

you can not do a "int i=0" , inside a block

you can do the following inside of the block:


int i;
i=0;


but the i remains in scope after the block.



doesn't the above violate the first 2 rules you gave ?

galathaea
October 21st, 2002, 01:06 PM
This is why you should either declare the variable at the head of the block, or create a new block inside. This was the point of my switch example earlier. The design principles are not followed, and goto had nothing to do with these problems. I am wondering if, by FOLLOWING the design principles, one can do anything mischeivous with goto.

Philip Nicoletti
October 21st, 2002, 01:23 PM
So if you declare a new block inside, what
exactly is the point of the goto and the label ?


if (...) goto here;
{
...
}
here:


Removing what is in bold above leaves the standard "if() {}".

Then later you need to add an "else" block - it really starts
to get to be a mess. Sorry, but this use of goto of your is
definitely bad.

(You'll notice I am saying this particular use of goto is
bad, not all uses. But it is uses like this that have
caused people to want to never use them.)

jfaust
October 21st, 2002, 01:31 PM
am wondering if, by FOLLOWING the design principles, one can do anything mischeivous with goto.


That's a big 'if'. That's not something that is easily guaranteed, no matter how many code reviews you do. I would guess that most products don't and won't follow these principles.

Theoretically, you may have a point. In practice, I believe the use of goto will degrade the maintainability of a product because when not following the principles you mentioned, goto will be a more serious problem than other flow of control structures.

Jeff

galathaea
October 21st, 2002, 01:35 PM
What exactly about the goto is bad but the if good? What I am getting at is that this is just a code fashion preference. Some might say to use a switch, some if, some goto. The reason I picked this as an example is that it precisely relates to these issues and does not give goto an unfair advantage (such as stepping out of nested blocks, which allows one to exit without the need to pollute variable namespace and does not make the original logic more complex with variable tests to exit). I understood completely that the fragment I posted was possible in many other ways. What I desire, though, is a reason why it is worse than the alternatives. Each alternative has its own blocking structure that may or may not be useful. I personally would use an if on the occasion that I needed to declare more variables, because it provides the proper block structure I desire. Remember, I didn't put any variable declarations in my original code. But I still would not have a problem if one of my developers submitted something like that.

So, why is goto bad but the if good?

jfaust
October 21st, 2002, 01:45 PM
goto is an unconditional branch that is separated from the reason for the branch. Other control structures have the reason built in.

Jeff

Yves M
October 21st, 2002, 02:38 PM
One thing is also that goto has no programming logic built into it. When you see a for loop you know what it is. When you see an if () statement you know what it is and how it behaves. When you see a goto, it could mean pretty much anything.

The goto statement doesn't hold any information about what the semantics of the code are. This is a loss when you could use a statement that has in-built semantics.

This does not mean I'm entirely against goto in all cases, but most of the time it's clearer to use a more appropriate statement. Of course this hasn't been said before :D

galathaea
October 21st, 2002, 03:27 PM
jfaust, I concede to your superior debate move. Absolutely! It makes absolute sense. Because it should be a design principle that one should keep a branch connected to the logic of the branch. And so, this design principle invalidates the use of goto ever. Of course, I could argue that one could still use goto if the branch condition is connected to the goto in a complete statement group (if, goto) but then you have maintainability issues. Brilliant!

** galathaea spins melodramatically at the fatal shot to the heart **

Whispered, last gasp: "I have been fell by the greater rhetorics of jfaust. All should follow his advice. Never use goto."

jfaust
October 21st, 2002, 04:15 PM
galathaea,

You must be the most fun person to debate with. ;)

Thanks for pressing the issues--made me think more about it than I have before. It's always good to revisit 'beliefs', and see if there's any sense to them.

Jeff

AnthonyMai
October 21st, 2002, 07:57 PM
One thing is also that goto has no programming logic built into it. When you see a for loop you know what it is. When you see an if () statement you know what it is and how it behaves. When you see a goto, it could mean pretty much anything.


Some times less information is better information. I do not think goto mean "pretty much anything". It has only one unambiguious meaning: Jump to where label specifies.

Your boss may tell you: step outside the office door, make a left, go downstairs, make a right, exit the building, left turn into a place where a lot of cars are parked, get in your car, exit the parking lot and get on the highway, etc. etc. All these are very specific and very detailed information but the more specific it is, the more confused you will be. You boss might just tell you to "go home and come back tomorrow". It's a much less specific instruction but it is much less confusing.

goto is pretty useful and helps readability where there are multiple opening and closing curly brackets ({}'s) between the goto statement and where the goto label is. It is more so when the code is badly formatted and it is hard to match opening and closing {'s and }'s.

See this code:


//...
break;
}}}}}}
//..
{
//..
// A couple hundred code lines.
}}

here_we_go:


So by reading the above code, how is it clear to you that when it hit the break statement, it will break all the way out of all the {'s and }'s and lead you next to here_we_go?

To reach that conclusion, you would have to look at each { and }, find its matching partner, and look at whether it is a for loop, a if/else or a while, and decide whether you should break out of that scope. If there are a dozen of them, and the opening and closing {}'s are several hundred lines apart from each other, plus they are not formatted to be aligned with each other, you will have a VERY DIFFICULT TIME figuring out where you go, after the break statement.

Where as if I used goto, it's going to be a no-brainer where I go next.

Yves M
October 22nd, 2002, 06:30 AM
Well, if I would take that point further, I would never use break in any program since that statement also doesn't hold any semantics. You pointed this out quite successfully in your example.

But, the point I was trying to make about goto is that if there is an option with semantics, prefer that one.

As to my statement that goto can mean anything... It depends on how the programmer uses it, but as you know assembly, you know what you can do with unconditional jumps. So well, let's say pretty much anything ;)

if (i == 5) goto label_true
result = 16;
goto label_end
label_true:
result = 25
label_end:

if-then-else loop for example


i = 0;
label_loop:
if (i >= 5) goto label_end
result = result * i
goto label_loop
label_end:

for loop...


for (i = 0; i < 5; i++) {
if (i == 3) goto label_break
}
label_break:

the break example...

etc...

P.S. I actually never use break in any program ;) There is nothing evangelical about it but I just don't find the need for it.

arkadi
February 13th, 2004, 12:20 PM
Hi, all. Here one reason to use "goto":

Say you have long sequence of system calls.
Each system call you have to check return value.
If system call failed, the rest of sequence is useless,
but you have to clean-up some handlers.

With ussage of goto, the code is like this:

if (sys_call1(param) == -1)
goto cleanup;

if (sys_call2(param) == -1)
goto cleanup;

if (sys_call3(param) == -1)
goto cleanup;

if (sys_call4(param) == -1)
goto cleanup;

cleanup:
free_param(param);

Now, with C++ you have alternative - throw exception.
Or you can split it to set of subfunctions and do cleanup
in other function at all.
Both alternative solutions that I see are longer and harder.

Do you have better solution ?

arkadi
February 13th, 2004, 12:26 PM
Hi, all. Here one reason to use "goto":

Say you have long sequence of system calls.
Each system call you have to check return value.
If system call failed, the rest of sequence is useless,
but you have to clean-up some handlers.

With ussage of goto, the code is like this:

if (sys_call1(param) == -1)
goto cleanup;

if (sys_call2(param) == -1)
goto cleanup;

if (sys_call3(param) == -1)
goto cleanup;

if (sys_call4(param) == -1)
goto cleanup;

cleanup:
free_param(param);

Now, with C++ you have alternative - throw exception.
Or you can split it to set of subfunctions and do cleanup
in other function at all.
Both alternative solutions that I see are longer and harder.

Do you have better solution ?

jfaust
February 13th, 2004, 12:35 PM
Originally posted by arkadi
Do you have better solution ?

Yes. You are trying to do too much in one method. Break it up. Have one simple well-defined purpose per method. If you have system calls that allocate memory, wrap that logic in a simple class that handles the deallocation in the destructor. There are several things you can do to clean this up, even if you ignore the use of goto.

Besides, I don't think your contrived example is valid. You are allocating memory several times and only freeing it once.

Jeff

arkadi
February 13th, 2004, 12:59 PM
Besides, I don't think your contrived example is valid. You are allocating memory several times and only freeing it once.
You know, it`s pseudo code :)

param = malloc(size_param);

if (sys_call1(param) == -1)
goto cleanup;

if (sys_call2(param) == -1)
goto cleanup;

if (sys_call3(param) == -1)
goto cleanup;

if (sys_call4(param) == -1)
goto cleanup;

cleanup:
free(param);


Break it up. Have one simple well-defined purpose per method. If you have system calls that allocate memory, wrap that logic in a simple class that handles the deallocation in the destructor
Yes, it is solution. But:
Does it make code cleaner ?
Does it make writing code faster ?
When you come to somebody`s old code, what do you prefer:
10 strokes that uses "goto"
or 50 that implements work-around ?

jfaust
February 13th, 2004, 01:50 PM
Originally posted by arkadi
Does it make code cleaner ?

Yes.

Does it make writing code faster ?

Almost always not an issue. And if it is, inlining can solve it.

When you come to somebody`s old code, what do you prefer:
10 strokes that uses "goto"
or 50 that implements work-around ?

I'm not talking about implementing a work-around. "Not using goto" is not a work-around. It's a good coding practice for all the reasons brought up previously. Wrapping resource in objects that free the memory on destruction is also a good practice--look up RAII for more information.

When all of this is done, your example could be less than 10 lines, and certainly not 50.

Jeff

KevinHall
February 13th, 2004, 02:05 PM
I've worked on systems where error handling needed to be done like that. Actually, rather than using gotos, the following code was used:


int aFunction()
{
int res;

/* Some enter function trace statements */

res = fn1();

if (res == 0)
{
res = fn2();
}

if (res == 0)
{
res = fn3();
}

if (res == 0)
{
res = fn4();
}

/* ... */

/* Some cleanup */

/* Some exit function trace statements */

return res;
}


The need here was to maintain a single exit point for the functions so that traceing would work -- and the functions WERE split up appropriately with good structure. Personally, I think that goto's would have performed better when an error did occur. However, the argument against this was "we only care about performance when things are working as they should." This seemed to be valid for the application in question.

- Kevin

arkadi
February 13th, 2004, 02:05 PM
When all of this is done, your example could be less than 10 lines, and certainly not 50.
While other reasons are matter of taste, this can be shown.
Please, submit your solution.

jfaust
February 13th, 2004, 02:38 PM
Originally posted by arkadi
While other reasons are matter of taste, this can be shown.
Please, submit your solution.

More than a matter of taste. We've tried to show the dangers of using goto. But anyway, here's my solution. The code provided above was not a real-world example, so neither will this be a real-world solution. Most importantly, the names will not be meaningful.


// should use a more meaninful name
class ResourceAquirer
{
public:
ResourceAquirer()
: m_param(0)
{
}

~ResourceAquirer()
{
if( m_param )
free(m_param);
}

// this would be a more meaningful method, perhaps returning
// the string from the registry.
res_type getResource() const
{
// The logic goes here to allocate the resource if it has not
// been already, aka lazy evaluation/initialization.
if( m_param )
{
return m_param;
}

m_param = malloc(param_size);

// Now get the resource. Note there's no need for a
// cleanup section since the memory is freed in the
// destructor, hence no desire to use goto.
}

private:
res_type m_param
};

int aFunction()
{
ResourceAquirer r;
if( res_type res = r.getResource() )
{
// use resource or better yet, put the logic into
// the ResourceAquirer class to use the resource.
}
}


Now we have a reusable class that maintains the logic and the memory of aquiring a certain resource. This can be safely reused where needed. Note the user does not have to ever worry about freeing up any resource. It will be freed for him, even in the face of a thrown exception.

Jeff

arkadi
February 13th, 2004, 02:43 PM
Ok, it`s not 50 lines, it`s 47 :)

My sample was not about resource management.
It was about error handling.
Do you have ideas about error handling ?

jfaust
February 13th, 2004, 02:52 PM
Originally posted by arkadi
Ok, it`s not 50 lines, it`s 47 :)

Sure, if you count the reusable code with that. If you are looking at it from the method level, we've got 3 lines that does everything your original logic did. This is an important distinction. When you are debugging, after you know ResourceAquirer works, you can ignore it wherever it is used. You can ignore all that code and more quickly zero in on the real problem.


My sample was not about resource management.
It was about error handling.
Do you have ideas about error handling ?


Your example was about resource management and error handling. And so was my answer. If you encounter an error in my example, you can simply return. Any allocated memory will be freed via the destructor call. Same goes for a thrown exception.

Jeff

arkadi
February 13th, 2004, 03:11 PM
Sure, if you count the reusable code with that.
Yes, your code could be reused and some libraries implements that.
But it is not part of standard libraries yet.

What could you do if resource is file or socket handle ?
I quess you will improve your "ResourceAquirer".

What you do if clean-up is: close handlers and
after that remove one of temporary files or directories ?
Could your code be yet universal ?
Yes, you can do it universal.

All that end-up with pretty complex library that do everything.

The kind of my code is frequent case for test programs.
Do you think to add your library on each your test ?

Do you think the code using some monstrous library wroten
by unknown author is simplier than 10 strokes of simple code
that uses "goto" ?

jfaust
February 13th, 2004, 04:24 PM
Originally posted by arkadi
Yes, your code could be reused and some libraries implements that.
But it is not part of standard libraries yet.

I'm not talking about writing a standard library. I'm talking about using well-understood and accepted techniques to manage memory and handle errors. Avoiding goto is just a nice side-effect.

What could you do if resource is file or socket handle ?
I quess you will improve your "ResourceAquirer".

I would write a Socket class. I would write a File class. These classes would control the allocation and deallocation of system resources.

What you do if clean-up is: close handlers and
after that remove one of temporary files or directories ?
Could your code be yet universal ?
Yes, you can do it universal.

Correct, however I don't like the idea of doing too much in destructors. You have to be very careful that destructors never ever throw exceptions or cause exceptions to escape.

All that end-up with pretty complex library that do everything.

Not complex. It does not have to do everything. As your software needs more functionality, it can be added.

The kind of my code is frequent case for test programs.
Do you think to add your library on each your test ?

I think it would make perfect sense to reuse this for test programs.

Do you think the code using some monstrous library wroten
by unknown author is simplier than 10 strokes of simple code
that uses "goto" ?

I don't know where you get "monstrous" from, or where you get "unknown author" from. Software projects have source control with history. Good code has comments and follow accepted idioms (in this case, RAII).

Yes, I think a Socket class that wraps calls specific to the application you are working on is "simpler" than doing it by hand each time.

Your code is not exceptions safe. The memory will not be freed if an exception occurs. Your code cannot be reused (aside from copy and paste). Your code is not self-documenting. If it was in a class called "Socket" in a method called "open", you know what it's trying to accomplish even before you examine the code. But the best part is, you may never even have to look at the code! If this class is used elsewhere correctly, you can feel pretty confident that it works correctly.

Yes! It's simpler!

Jeff

CornedBee
February 13th, 2004, 05:18 PM
The use of more than one statement with any of the "good" keywords require braces, which mark the code section affected by the keyword. goto has no such requirement, and in fact it might be impossible to place such braces if there is more than one goto.



There are a few gotos in the MS CRT implementation of printf (actually output, which lies at the heart of all the *printf functions) btw.

arkadi
February 14th, 2004, 12:49 AM
There are a few gotos in the MS CRT implementation of printf
Nice argument.
In g++ implementation you have it even more
( see "iovprintf.c"::_IO_vfprintf ).

But lets get back to theoretical issues.
I don't know where you get "monstrous" from, or where you get "unknown author" from.
If author of code is not hired few years, its name in documentation is almost meaningless.
Hence I stand on "unknown author".

About "monstorous" ... well, at it start it must not be.
It could be rather big.
With few iterations it can become monstour, but if you do
some hard administrative effort, you can avoid that for few years.

About RAII. Here is a quote from http://www.hackcraft.net/raii site (I hope you trust that site while talking of RAII):
However once the class is tested, trusted, and well known these can be stepped over and the task of stepping through code is simplified.
There are some other drawbacks if class is not "tested, trusted, and well known".

The problem appear when none of that prerequirements are valid.
If you prepear basis for some application that will be in OO design, you will be able to prepear "tested and trusted" library.
But even you switch to other project I have a suspect if you
could be able to use the same code.

Finally:
1. You have to create library.
2. You perform non-trivial administrative effort to keep it consistent in all projects.

Question is what you get back ?
1. Less code is for sure not - your library is code too, even if it is standard for you.
2. Argues with other developers that don`t like your implementation.
For example thay don`t like your naming convention :)
3. Hence library is not trusted and not sure if tested,
you get trobles in debugging logic code for other developers.
Your peace of troubles you get while implementing the library :)

CornedBee
February 14th, 2004, 05:35 AM
#2 is invalid - I'm sure you get a lot more arguments with other developers if you use goto.
#1 is not so sure. If it's something very common (like smart pointers), you get a lot more back than you put in.
#3 isn't so sure either. A simple RAII class is very easy to implement.

arkadi
February 14th, 2004, 01:24 PM
I'm sure you get a lot more arguments with other developers if you use goto. If they don`t have to bother with your code at all, they have nothing to argue about.

If it's something very common (like smart pointers), you get a lot more back than you put in. The difference form smart pointers (like ATL) is that smart pointer classes are tested by vendor and trusted by each developer after it`s own positive expirience with it.

A simple RAII class is very easy to implement. Usually yes, but you have to do it.
And as any code it can be buggy :)
Again it`s matter of testing and trust.

IntoWind
February 22nd, 2004, 06:27 AM
i think if you write a function with many goto
1.you will not be able to understand your function when you saw the function you writed many days ago.
2.ussually lead to fault

JeffAust17
February 22nd, 2004, 07:10 AM
I now in high school but my C++ book says so many goto not good, i think iit not be good to use,

Sincerely

Jeff

CornedBee
February 22nd, 2004, 08:01 AM
If they don`t have to bother with your code at all, they have nothing to argue about.
What if you're on a team?

arkadi
February 23rd, 2004, 02:14 PM
Answer for JeffAust17 and IntoWind:
goto is dangerose thing and must be used with extreme
care and ONLY if you exactly know what for you need it.
In most cases it can and should be replaced with other
language forms.
That`s why you will never find in C book for beginers
advice to use goto. It will be very bad advice.

For CornedBee:
What if you're on a team? The best team for man is a man himself.
The program should be devided to modules and modules to functions.
The module (I guess in your case classes :) must be self defined
peace of code with well defined external interface.
The similar rule for function - it have to do one thing and to do it best.
All that general rules of any design that allow several people to share code.

If you do the function with "goto"`s with well defined parameters and well defined behaviour, the maintanance will not be a problem even by other programmers.
On other hand if you do seemingly simpler function, but with interface that is big library - here you have a problem. Specially if that library is not too mach tested and trusted.

CornedBee
February 23rd, 2004, 02:24 PM
I disagree. While you may be only one working on your module NOW, in the future someone else from the team might be transferred to help you out. In general, because programmers can shift, a single coding standard should be agreed upon for all modules and all code before the actual start of coding. And then you have to justify the use of gotos for the other developers.

KevinHall
February 23rd, 2004, 02:26 PM
Have you guys read the debate earlier in this thread between Galathaea and jfaust? I believe their arguments and conclusion are worth noting:

Originally posted by jfaust
goto is an unconditional branch that is separated from the reason for the branch. Other control structures have the reason built in.

Jeff

Originally posted by galathaea
jfaust, I concede to your superior debate move. Absolutely! It makes absolute sense. Because it should be a design principle that one should keep a branch connected to the logic of the branch. And so, this design principle invalidates the use of goto ever. Of course, I could argue that one could still use goto if the branch condition is connected to the goto in a complete statement group (if, goto) but then you have maintainability issues. Brilliant!

** galathaea spins melodramatically at the fatal shot to the heart **

Whispered, last gasp: "I have been fell by the greater rhetorics of jfaust. All should follow his advice. Never use goto."

The reason why goto's should be avoided is that a goto branch is not connected to the logic of the branch, leading to maintainablity problems and the increased likelyhood of bugs.

_uj
February 24th, 2004, 09:05 AM
Originally posted by KevinHall
The reason why goto's should be avoided is that a goto branch is not connected to the logic of the branch, leading to maintainablity problems and the increased likelyhood of bugs.

Fine but what does it mean? Separated from what logic. A goto is used to interrupt the normal flow of other control structures, but so is a break statement. There's no difference in principle. It's just that break has got a fancy name and become accepted over time. It's still a goto, as structured programming affectionados can tell you.

To use a goto once in a while as an extended break (jump to the exit point of a block) isn't the end of the world. It can even improve code because it can reduce the structural complexity of for example nested loops.

jfaust
February 24th, 2004, 09:54 AM
Originally posted by _uj
Fine but what does it mean? Separated from what logic. A goto is used to interrupt the normal flow of other control structures, but so is a break statement. There's no difference in principle. It's just that break has got a fancy name and become accepted over time. It's still a goto, as structured programming affectionados can tell you.


'if', 'while', 'switch/case' and 'for' have built-in well-defined branching logic. These largely replace any need for 'goto'. But alone they are not enough. There are some cases where you need more control for the looping constructs. 'break' and 'continue' help this. They both have a single well-defined purpose. 'goto' has no single well-defined purpose. 'break' is to break out of the loop. 'continue' will start with the next iteration on the loop. 'goto' could be used for either of these, or to jump to some exit/error condition, or to jump into the middle of some other if statement, or anything. Hence, there is no single well-defined purpose for it. That's the difference. It is separated from the reason for the branch.


To use a goto once in a while as an extended break (jump to the exit point of a block) isn't the end of the world. It can even improve code because it can reduce the structural complexity of for example nested loops.


No, not the end of the world. An no, not every place it is used is a maintenance problem. And yes, it can be used conscientiously. I'll even admit there may be cases where it can reduce structural complexity. However, I have not seen such an example in ten years that couldn't be fixed by a better method than using goto. Before that, if I used it, it's only because I didn't know better.

'structural complexity' is a big concern of mine. I've always found a way to deconstruct complexity without resorting to goto. Take nested ifs as an example. There's usually a question you are trying to answer with the nested ifs. Maybe you are trying to get at an object through several layers and want to perform null checks on each layer. Maybe you are checking various statuses. Whatever the case, this logic can often be moved to a separate method.

'structural complexity' usually comes about because the method is trying to do too much. So, decompose the problem. Don't use goto. Future generations of maintainers will thank you.

Jeff

KevinHall
February 24th, 2004, 10:36 AM
A break is connected to the logic of the while or for loop.

_uj
February 24th, 2004, 11:18 AM
Originally posted by KevinHall
A break is connected to the logic of the while or for loop.

Yes in C++ it is but Java for example is more liberal. There you can jump out of any block and even define labels to break to (within limits) like this,

boolean b=false;
repeat: {
// ......
if (b)
break repeat;
}

It's quite interesting that Java is more permissive than C++, it so seldom is. I think the reason is to furher reduce the need for a goto statement, the greater evil. ;)

KevinHall
February 24th, 2004, 11:23 AM
Well, maybe the java people should post a thread in the Java forum about the evils of labelled break statements. ;)

_uj
February 24th, 2004, 12:05 PM
Originally posted by jfaust
It is separated from the reason for the branch.


The whole idea with the goto is that it's able to interrupt all other control structures at will. It's a very poverfull ability but this isn't why it should be avoided I think.

Structured programming is about complexity reduction and in some cases the goto, and it's cousin the break, actually does that. One example is when you jump out of nested loops and thereby simplify loop exit criteria.

The break is interesting because what you do is basically to trade logical complexity for structural complexity. With a break you make the loop exit criterium simpler, but you pay with a more complex loop structure. I personally find a few breaks easier to comprehend than a huge boolean exit expression with lots of and's and or's.

Well, I very much agree with what you say Jeff. I also think goto should be avoided, but I'm not that totally against. If you can accept the break you should also be able to accept the judicious use of a goto for a purpose. It's sloppy, lazy usage that should be banned.

jfaust
February 24th, 2004, 12:19 PM
Originally posted by _uj
If you can accept the break you should also be able to accept the judicious use of a goto for a purpose. It's sloppy, lazy usage that should be banned.

I can agree with that, even though I doubt I will ever see a need to use it myself.

Another difficulty with it is that it's hard to put in a coding standards for a development team. It's much easier to say "don't use goto." Every team has a mix of talent and different areas of expertise. You may accept a poor programmer with a mostly fortran background if that person is an expert in the field, especially for scientific applications. Coding standards become very important, and increases with the size of the team. Effective rules can't be ambiguous.

Code reviews don't really help because it's very difficult to tell somebody to change something that works. But if you have a coding standard that prohibits it, you can ask them to change it without feeling like you're stepping on any toes.

Jeff

_uj
February 25th, 2004, 06:35 AM
Originally posted by jfaust
Another difficulty with it is that it's hard to put in a coding standards for a development team. It's much easier to say "don't use goto."

I see your point, but it's not just the goto's is it? C++ offers you an almost unlimited opportunity to screw up. At least that's my first impression. I have a Java background and in that language most of the dangerous stuff has been left out. Unfortunately some of the useful stuff too. That's why I'm here. :)

/Ulrika

jfaust
February 25th, 2004, 11:06 AM
Originally posted by _uj
I see your point, but it's not just the goto's is it? C++ offers you an almost unlimited opportunity to screw up.


Certainly, but goto is much more likely to be misused. It can be employed in almost any scenario, but there are very few (if any) valid uses. And when misused, even when logically correct, creates a real maintenance headache. Moreso than any other C++ construct.

Except perhaps for compound ternary operators:

a = b ? c : d ? e : f;

:)

Jeff

Andreas Masur
February 25th, 2004, 03:54 PM
Originally posted by jfaust
Except perhaps for compound ternary operators:

a = b ? c : d ? e : f;

Well...that is actually one of my lifetime favourites...it has saved me so many 'if...else' keying... :cool:

jfaust
February 25th, 2004, 03:59 PM
Now don't make me mad, Andreas. You won't me when I'm mad. Veins start pulsing in my forehead and such.

Jeff

_uj
February 25th, 2004, 04:14 PM
Originally posted by jfaust
Certainly, but goto is much more likely to be misused. It can be employed in almost any scenario, but there are very few (if any) valid uses. And when misused, even when logically correct, creates a real maintenance headache. Moreso than any other C++ construct.

Except perhaps for compound ternary operators:

a = b ? c : d ? e : f;

I have a feeling the goto is just a minor problem in C++. On the level of structural programming it can wreak havoc of course but that's just on the C level. It's not a very big problem from a maintainance viewpoint really. The goto and the ternary operator must be very minor problems on the grand scale I'd say. The real problem with C++ must be at the OO side. How do you get a Fortran programmer to understand for example inheritance and how to use it correctly?