- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
And, uh, why is it ok to use them here?!
Admin
That's the point... It's NOT okay to use them here.
Admin
'K, I'm lost. Is the implication that the poster should have used
continue;
instead of
goto cont;
?
But continue; re-evaluates the loop condition...
I suppose something like
while (true)
{
if (sysmgr->getProcessCount() == 0)
{
break;
}
...
continue; // rather than goto cont
...
}
would work.
Admin
Part of the point is it's not ok.
Further, part of the irony is that he's using the 'cont' label as the target of his goto. He probably tried 'continue' but found it was a pesky compiler reserved keyword. In most C derived languages, the continue keyword jumps execution back to evaluating the conditional of whatever loop you're currently in, without carrying out the rest of the body of the loop. (He could have used the statement 'continue;' without goto labels to get the same effect.)
Admin
I guess that guy skipped the lesson when his class learned "break" and "continue" keywords... It seems it didn't miss the "goto" class, but he should have paid more atention to it!
Admin
A very weird case: He clearly knows about while loops and he seems to have spent a bit of time thinking about what needs to happen . . . wonder why he failed to implement this better? Oh yeah! He must be an idiot. [:^)]
The right solution of course is to encapsulate the logic for stopping these processes where they belong -- with the sysmgr (or barring that, in a wrapper for the sysmgr).
Admin
Well, at least he reinvented the wheel round. I think it is completely equivalent to "continue;". Can someone find a case where it is not equivalent to while and continue?
Admin
C++ implementing GOTO?!?!?
Now I have seen it all.
Admin
The only thing I can think of right off the bat is that using goto cont; will not re-evaluate the while condition. Is that not the case in this snippet?
Admin
As astutely pointed out earlier, the goto with the continue doesn't re-evaluate the condition of the loop, whereas 'continue;' would. For example, consider get(), if you evaluate it second time, you'll read the next character from standard input. With the goto construct you won't advance your position in the stream, with 'continue;' you do.
Admin
Admin
You mean when GOTOs are not the same as loop constructs (while/for)? Well I used it in a parser state machine once to save myself from function calls etc. It may have been a bit spaghetti-ish, but it ran really FAST. =]
Admin
Thanks, so actually it is a square.. :D
Admin
I always use COMEFROM statements instead of GOTO statements.
Admin
No timeouts when checking to see if the process is inactive. This could be by design, but judging by the comment ("may take up to 3 calls") I'd say it's not by design at all.
Also, since he's using goto instead of continue, he doesn't check to see if the process count is zero. So if I have one process, and it quits early...
Programmers this bad need to go back to Javascript. Maybe even XML. You can't do goto in XML.
Admin
Admin
Before writing such commentary, think about kernel code where gotos are used extensively. See, http://kerneltrap.org/node/553.
Admin
Yaknow, it's this little gem that really has me obsessing:
I love the TryInactivate (I'll ignore the use of Inactivate instead of Deactivate). "Try" indeed, clearly it fails sometimes! The WTF is that you have a method that may or may not work! Why can't the sysmgr do what it's told to do? Who writes like this? I mean, if it works then it works, if it doesn't, raise a !#$%!exception. Don't make me guess!
Admin
"Ok, is there a reason why this rewrite would be unacceptable?"
Yeah, why not? The rewrite looks very much different. I'm not going to check the logic; I'm a litle drunk, doing Boole's things makes my brain hurt. Moreover, in the original logic TryInactivate() can be called way more than 3 times: WTF? "I know, I'll pull i<3 out of my (*)!" Basically this is a very hairy case to rewrite. I'd find out the original programmer's e-mail address for this one. Also, after we ReuseCurrentProcess(), we're going to TryInactivate() it again. WhyTF this would be necessary, only Godess knows. Just CloseCurrentProcess() is not what the original programmer intended.
May I point out that using the continue or the break statement would be totally different from restarting the loop without checking the condition? The cont: label is right at the beginning of the loop, admittedly weirdly indented.
I think that goto's should not be considered harmful. If they were, every while, every if, and every logic of any kind would be harmful; they all get compiled to conditional jmp instructions. For this same reason pointers are not harmful. It's just how computers work. Now higher level languages have nice ways of avoiding goto statements. That's a case of 'using higher-level constructs considered wholosome'.
I think the best way to rewrite this piece of code is to move most of the loop body inside a function. I wouldn't really say this case of using goto is harmful; it keeps all the logic in one piece of code, not in two. But hten again, I'm a little drunkish. I'll try the rewrite, just for kicks. I'll note in advance that a goto is just a really cheap function call.
while( sysmgr->getProcessCount() != 0 )
{
// Yes, I realize "goto" statements are considered harmful,
// but this is a case where it is OK to use them
cont:
//inactivation is not guaranteed and may take up to 3 calls
sysmgr->CurrentProcess()->TryInactivate();
if( sysmgr->CurrentProcess()->IsActive() )
{
Sleep(DEFAULT_TIMEOUT);
goto cont;
}
/* ED: Snip /
//disconnect child processes
if( sysmgr->CurrentProcess()->HasChildProcesses() )
{
/ ED: Snip /
}
/ ED: Snip /
if( sysmgr->CurrentProcess()->IsReusable() )
{
sysmgr->ReuseCurrentProcess();
goto cont;
}
sysmgr->CloseCurrentProcess();
}
could, IMNSHO, be rewritten to:
while(sysmgr->GetProcessCount() != 0) {
DoTheImportantInactivatingAndReusing()
}
void DoTheImportantInactivatingAndReusing() {
sysmgr->CurrentProcess()->TryInactivate();
if(sysmgr->CurrentProcess()->IsActive()) {
sleep(DEFAULT_TIMEOUT)
DoTheImportantInactivatingAndReusing();
}
/ snip /
if(someconditionthatdoesntreallyapplybecauseofsnipping) {
/ snip /
}
/ snip */
if(sysmgr->CurrentProcess()->IsReusable()) {
sysmgr->ReuseCurrentProcess();
DoTheImportantInactivatingAndReusing();
}
sysmgr->CloseCurrentProcess();
}
There! Beautiful! Not harmful! No gotos anywhere. Instead of infinite loops, we'll have infinite recursion! But then again, beer. Hmm, duffs.
Admin
Technically, yes, but not functionally, from what I can tell. The condition that is checked should not change if the last line of the loop is not called (purely guessing from method names.) Even if that's not true, it appears that executing the body of the loop when the condition is false is wrong. So calling continue is different, in that it's better.
Admin
Ahhh.... GOTO. Where have you been?
This brings me back to the days of Apple IIe BASIC and TI-Basic on my calculator. I don't think I've ever really needed to use it in any other language. There are enough looping constructs out there that GOTO is 98% of the time unnesessary.
His comment should have read:
// Yes, I realize "goto" statements are considered harmful,
// but I'm too lazy/stupid to think of a better way to do this.
Admin
There are cases where goto is very useful, and actually helps readability. Non-throwing procedure calls can benefit:
void MakeDeviceObject()
{
int iErr;
iErr = GetDevice();
if( iErr == ERROR ) goto l_Err;
iErr = SetDeviceParameter( "Goblin" );
if( iErr == ERROR ) goto l_Err;
...
return;
l_Err:
DestroyDevice();
Log( "Error making device object!" );
}
Admin
OK, here's a goto-less version that does what I think he was trying to do...
bool docheck = true;
while (true)
{
if (docheck && sysmgr->getProcessCount() == 0)
{
break;
}
...
if (...)
{
// rather than goto cont
docheck = false; // skip the check
continue;
}
...
docheck = true; // made it to the end... repeat the check
}
Admin
Secondly, the "timeout" seems to be a "retry delay" -- we only want to pause for that time if the Deactivate failed.
Also, I'm gonna guess that "Current Process" is just one of getProcessCount() ... When one "Current Process" closes, another one becomes the new "Current Process".
I believe what we actually want here is :
No gotos, no continues, no breaks. One comment added, and one moved, so things make more sense.
Admin
Friends don't let friends code drunk. They end up on the Daily WTF.
Admin
Nope... You haven't eliminated the GOTO, you just renamed it.
All loops end eventually, on some condition. Get that condition into your while loop statement.
Admin
Picky, picky...
bool docheck = true;
while (docheck && sysmgr->getProcessCount() == 0)
{
...
if (...)
{
// rather than goto cont
docheck = false;
continue;
}
...
docheck = true; // made it to the end, reset
}
Admin
This is a first: I don’t consider the code a WTF at all. It could have been written better, sure, but without knowing if re-evaluating the condition is undesirable and how long the snipped code was, it does not warrant a WTF.
As for
GOTO
, I have this to say:Admin
How is that any better than this:
void MakeDeviceObject()
{
try
{
GetDevice();
SetDeviceParameter( "Goblin" );
...
}
catch(DeviceException)
{
DestroyDevice();
Log( "Error making device object!" );
}
}
Admin
Well, since, as Trev stated, GetDevice() & SetDeviceParameter() do not throw exceptions, the code in your catch will never be executed (but SetDeviceParameter() will probably fail spectacularly when GetDevice fails gracefully)
Admin
Actually...
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csref/html/vclrfthegotostatement.asp
Now you've seen it all.
Admin
v3: use a for loop instead
for (
bool docheck = true;
docheck && sysmgr->getProcessCount() != 0;
docheck = true;
)
{
...
if (...)
{
// rather than goto cont
docheck = false;
continue;
}
...
}
Admin
Ok, this is kind of freaky that this showed up. Last week, a coworker and myself were discussing the C# switch statement and the use of break inside of them. I mentioned that a great WTF would be if we came across something like this (forgive any syntactical errors for now)
Switch (myVar)
{
case 1:
doSomething();
goto endswitch;
case 2:
doSomethingElse();
goto endswitch;
case 3:
doSomethingDifferent();
goto endswitch;
}
endswitch:
I know it's a bit different and this is not code that we actually came across, but since we were just talking about the use of goto's and now it shows up in WTF is a bit spooooooky. Like they were reading our minds.
Admin
this site always makes me feel good about myself.
Admin
Oops v3.1
for (
bool docheck = true;
docheck && sysmgr->getProcessCount() != 0;
// DON'T docheck = true here as "continue" will fire it
)
{
...
if (...)
{
// rather than goto cont
docheck = false;
continue;
}
...
// OK to put it here though
docheck = true;
}
Admin
I have to agree with this. This might be a "Huh?" but not a "WTF?"
Admin
You could always throw you own exception. Generally, I would just create a new method, though.
Admin
The thing about the 'gotos are sometimes necessary' argument is that Java doesn't allow gotos yet I've never heard of a single one of the thousands of Java projects failing for the want of a goto.
So until someone can show me a code snippet that uses gotos and cannot be rewritten not to use them, I have to believe that gotos are never necessary. I've not used a single one since I learned to program in basic. I've never even desired to use them. I don't even use labelled breaks. Never wanted to.
Admin
Well, I was bored at work, so I figured I'd give it another go:
If you're having trouble following the line
<FONT face="Courier New">while(sysmgr->CurrentProcess()->IsActive() && (Sleep(DEFAULT_TIMEOUT), true));</FONT>
don't feel bad. I'd probably consider it too WTF-ish to actually use in production code. Here's the translation for the "Obfucated C" impared:
<FONT face="Courier New">sysmgr->CurrentProcess()->IsActive()</FONT> is the condition we want to check. Since it's joined to the rest by an AND condition, if it's false, the whole expression must be false, and we exit the loop without evaluating the rest of it..
<FONT face="Courier New">Sleep(DEFAULT_TIMEOUT), true</FONT> The comma operator means "evalutate both parts, then use the expression on the right, as the value of the whole expression. In other words, first we sleep for a bit, then we declare the sub-expression to be true. Since both halves the expression were true, we continue looping. Now, if Sleep could be counted on to reliably return a !=0 value, we could make while clause shorter and even more confusing! (On the other hand, however, I believe if Sleep returns void, I think we're just screwed, and it won't even compile)
Admin
Well put!
Admin
Actually, going back even further, dBase III didn't have a GOTO either. (well, it's actually did has a keyword named "goto", but it's not what you think ... it moved the active record in the database to a different row). And there's been a lot more code written in dbase III then in Java.
The problem is not if it can or cannot be rewritten without them, but can it be rewritten better by removing them.
Admin
Libraries in Java throw exceptions when exceptional cases happen. C++ doesn't have that advantage; any library that's designed to be compiled in either C or C++ (many) will not throw exceptions (unless it's using SEH, which is not portable). So, you look at return values. The example I posted above is used a lot in Win32 and DirectX programming where lots of calls in a row can fail for some reason, and you just want to back out.
"goto is evil" is pure dogma. Any feature is only as bad as the worse use of it. If used well, it's perfectly fine.
Admin
Actually...
Perl stole this idea from FORTRAN:
Admin
I feel pretty confident that given a piece of code that uses gotos, I can structure the code in a way that doesn't use them and is at least 'as good'.
Every example I've seen to this point have been straw man examples. Examples of how gotos make bad code marginally better. They are too long or do too much or should be replaced with a different approach entirely orientation.. I could be wrong, but gotos seem to come from habit or a lack of imagination i.e. being locked into a procedural mindset.
Admin
Well, for one thing, your code is illegal in C… in languages without exceptions,
GOTO
can be the only maintainable and readable way of cleaning up allocated resources.Admin
If you do not have exceptions, I see using gotos for that purpose as perfectly acceptable.
I don't see gotos as evil. I don't worship at the altar of structured programming. I've programmed microcontrollers and in machine language and understand that basically anything that is useful is a jump. There are lots of perfectly accpetable uses of gotos. My thing is that 'thouroughly modern' languages have formalized all of the really useful and acceptable uses. So if you don't have all the modern tools at your disposal (notably exceptions) then you have to make do.
Goto is a swiss army knife. The problem is that when you are making sushi with a swiss army knife the blad my close on your hand and then you bleed all over the sushi. Then your dinner is ruined and you have to order a pizza and the pizza guy gets mugged because you live in a bad neighorhood and he shoots some poor kid who had a toy gun and then the kids mom gets really sad. Do you want to make the mothers of poor kids sad? Do you?!
Admin
Well, I certainly prefer this:
over this:
Procedural mindset? What else would you use in C? Sure, I’ve never needed a
GOTO
in Perl either.Admin
I think the best illustration of this point was made by Robert Love (kerneltrap)
From: Robert Love
Subject: Re: any chance of 2.6.0-test*?
Date: 12 Jan 2003 17:58:06 -0500
On Sun, 2003-01-12 at 17:22, Rob Wilkens wrote:
> I say "please don't use goto" and instead have a "cleanup_lock" function
> and add that before all the return statements.. It should not be a
> burden. Yes, it's asking the developer to work a little harder, but the
> end result is better code.
No, it is gross and it bloats the kernel. It inlines a bunch of junk
for N error paths, as opposed to having the exit code once at the end.
Cache footprint is key and you just killed it.
Nor is it easier to read.
As a final argument, it does not let us cleanly do the usual stack-esque
wind and unwind, i.e.
do A
if (error)
goto out_a;
do B
if (error)
goto out_b;
do C
if (error)
goto out_c;
goto out;
out_c:
undo C
out_b:
undo B:
out_a:
undo A
out:
return ret;
Now stop this.
Robert Love
In case it was not clear, say you have three tasks to do, and if you fail any of them, you want to roll your changes back. The above code is a simple way to do this without a lot of indentation, and it's efficient from a CPU point of view.
Admin
Although modern C++ has exceptions, there are valid reasons why a particular shop might choose to eschew them. On the other hand, straight C (which this could very well be) does not have exceptions.
Admin
Okay, I suppose there is no actual argument then.