- 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
Labeled breaks/loop control statements can be quite nice in Perl. I think they're even required to be labeled.
But then again, Perl seems to be a bastard language to some on this forum. [:)]
Admin
They don't have to be labeled.
Admin
I've had to maintain so horribly written code, I can't even imagine using perl on multi-person projects. It's just too wide open.
I guess that's why I like Java. I don't have to lookup syntax. There's only a one way to write most things in terms of the syntax. I work on code that has dozens of poeple in it, a lot of whom I've never met and often don't know their names (current developers, not just legacy) so the more we can limit the trouble they can get into, the better.
Admin
Of course Java has go-to's, they're called "Label statements" but they're go-to's just the same.
I find the programmer who yells "you can't use go-to's!" the loudest usually can't explain why.. it's quite reminicent of that management-monkey comparison involving a ladder and bananas.
Admin
Totally backwards.
for(bool doCheck = true; !doCheck || sysmgr->getProcessCount !=0; doCheck=true)
{
if(!sysmgr->hasPorkRinds)
{
doCheck = false;
continue;
}
}
yes, continue resets doCheck back to true, however, this is a desirable effect, as continue thus will behave normally if called subsequently in a situation where conventional continue behavior is wanted.
With your setup, using continue would be effectively equivalent to using break, as setting docheck to false would cause the test to fail completely and terminate the loop.
Admin
Last post was in regard to Mauritis' solution. Damn this board software!
Admin
No, they are no gotos. They, like if, switch, throw, while etc.do one thing that you can do with gotos but they aren't gotos.
In any event, like I said, I don't like them and haven't once used them in five years of programming in Java. To this date, no one has shown me a good example of when they are better or necessary. So until you can put your money where your mouth is, anonymous coward, I'm not impressed.
Admin
Yeah, to be honest, I've never seen any really large projects done in Perl. MovablType is an exception, but I don't think they have a large staff.
Admin
Oh, but anything can be rewritten in assembly, so every single high level construct (and thus every single programming language) is unnecessary.
Admin
doCheck && ... vs. !doCheck || ... yes, you're right. Silly me.
"continue" reseting doCheck back to true - no, you're wrong. If you do a continue, the third thing in the for loop is executed BEFORE evaluating the second thing in the for loop. So the third chunk of the for loop should be a no-op, and the doCheck = true should appear at the end.
Admin
The #1 good use of goto is to implement a very simple and low-overhead version of exception handling. The following C code could be rewritten without goto, but it would be much longer and uglier.
Without the gotos, you would have to repeat the call to releaseBacon() 5 times, releaseLettuce() 4 times, etc. Futhermore, when some later programmer comes along and decides that obviously bread should be allocated first, (s)he only has to reorder the error handleing in one place - thus reducing the odds of him/her getting it wrong and creating a fixins leak.
/* what a silly example */
struct sammich *get_sammich(int *err) {
struct bacon *thebacon;
struct lettuce *thelettuce;
struct tomato *thetomato;
struct bread *thebread;
struct sammich *thesammich;
thebacon = getBacon();
if (thebacon== NULL)
goto out1;
thelettuce = getLettuce();
if (thelettuce == NULL)
goto out2;
thetomato = getTomoto();
if (thetomato== NULL)
goto out3;
thebread = getBread();
if (thebread == NULL)
goto out4;
/* all resource allocations successful! */
thesammich = make_sammich(thebacon, thelettuce, thetomato, thebread);
if (thesammich == NULL)
goto out5;
/* yummy */
return thesammich;
out5:
cleanupSammich();
out4:
releaseBread();
out3:
releaseTomato();
out2:
releaseLettuce();
out1:
releaseBacon();
syslog(LOG_EMERG, "%s\n", "get_sammich failed!!!");
return NULL;
}
Admin
GOTO Hell.
Admin
Preview should let you see if if 3 other people said the same thing (better) before you got done writting a post. :P
But hey, at least mine was whimsical. :D
Admin
ermmm... he said "Non-Throwing Procedure calls". Your code won't do much good when DeviceException doesn't get thrown at all. And not every language even has exceptions
Admin
Actually Java does have gotos, as does the JVM. It just wont allow you to compile it.
Run a class binary through a de-compiler and enjoy the gotos in the resulting code.
Admin
You're confusing Java code with Java bytecode. Java bytecodes have gotos. Java code does not.
Admin
I'd be inclined to write this without goto, and break the usual indentation rules instead:
thebacon = getBacon();
if (thebacon!= NULL) {
thelettuce = getLettuce();
if (thelettuce != NULL) {
/* snip */
}
releaseLettuce();
}
releaseBacon();
which also allows tear-down to be re-ordered without having to change indentation.
If you can afford the overhead, then you should consider making the releaseFoo() functions NULL-safe and calling them all on failure, so that the order of tear-down need not be kept in sync with the order of build-up.
Admin
IMO it's no more readable, and less flexible. *shrug* Just a style at that point, but breaking language structure (even if just a little) just to avoid something valid for no real reason seems more obfuscating. Yes, it's easy to abuse goto. But using goto isn't necessarily abuse.
Admin
Yep, the old "goto". The refuge of coders who don't know how to plan a function or method. Nothing like seeing coding styles I first saw in the 1970's....
Admin
Well, have pity on us java guys, we have to make do with labels and named break/continue...
Admin
Why don't you just use try catch constructs?
Admin
Or have a new method?
Admin
Well, the "technical" reason why GOTOs are "bad" is because they make formal verification of program logic difficult. I don't know if they even teach formal verification classes any more, but that's where I saw the purely logic-based explanation of why they should be avoided. Formal verification isn't used in most places, but I find that when you are relying on GOTOs, it's usually because you don't have a clear idea of what you are doing or you haven't really organized your code properly.
Admin
Livejournal is also primarily written in perl, plus C and their own bizarro BML as well. And that is a huge codebase. (That's probably why they hooked up with sixapart, Perl geeks belong together.)
thalience seems to get it; try/catch/finally are thinly veiled structured gotos, which give you the power to implement them in normal C code, and can actually make code cleaner than cleanup in a catch/finally block, but only if implemented correctly and consistently. (Macro time.)
The original code is just a really bad use of gotos by someone too new or drunk to think through the proper sequence of booleans to arrive at his result.
It's standard (lazy) VB error handling in C. The obvious collary is that it's possible to have C/C++-style error handling in VB, with some effort. I've seen examples of such online.
Admin
Bah.
Although in C++ you would probably solve the problem with RAII. And personally, I've never run into a need for anything like this (which is always the common example) "in all my years".
Admin
Actually, it's used quite a bit --- by the optimizer built into every modern compiler. The better the compiler can track the usage of variables, the better it can optimize the code. Loop structures make it easy to track variable lifetimes. Gotos confuse the analysis.
Admin
Well, in Java programs people usually don't care about performance or well-structured control flow. (note: I think some uses of goto are good because they make the program easier to understand and reason about, and clearer programs are IMHO a Good Thing(tm))
For an enlightening discussion about possible valid uses of goto-statements, I would recommend the following article:
It gives an overview of the common uses of goto, and the equivalent goto-less programs. One observation that is made (shown in other papers) is that one has to do more computation of use more variables if goto's are to be avoided.
Admin
Bah again. In the case where the resources don't have to be cleaned up on success (as here), it's even easier:
struct sammich *get_sammich(int *err) {
struct bacon *thebacon = getBacon();
struct lettuce *thelettuce = thebacon && getLettuce();
struct tomato *thetomato = thelettuce && getTomato();
struct bread *thebread = thebread && getBread();
if (thebacon && thelettuce && thetomato && thebread) {
/* OK, we can try to make a sammich. */
struct sammich *thesammich = make_sammich(thebacon, thelettuce, thetomato, thebread);
if (thesammich) return thesammich; /* yummy */
}
/* We definitely don't ever have to clean up thesammich on failure, because
it is null :s */
if (thebread) releaseBread();
if (thetomato) releaseTomato();
if (thelettuce) releaseLettuce();
if (thebacon) releaseBacon();
syslog(LOG_EMERG, "%s\n", "get_sammich failed!!!");
return NULL;
}
But really, who uses C these days anyway? And even then, I say the release functions are at fault for not being able to handle (i.e. ignore) a null pointer input.
Admin
I thought (true_thing && another_true_thing) returned Boolean true,
rather than another_true_thing. Even if it does return
another_true_thing, the following would be clearer:
if (res1) res2 = alloc_res2( res1 );
if (res2) res3 = alloc_res2( res2 );
if (res3) res4 = alloc_res2( res3 );
if (res4) res5 = alloc_res2( res4 );
Actually, it should probably be
if (res1) res2 = alloc_res2( res1 );
(I'm guessing that Aristotle intended to use those functions,if (res2) res3 = alloc_res3( res2 );
if (res3) res4 = alloc_res4( res3 );
if (res4) res5 = alloc_res5( res4 );
but copy+pasted and missed making the appropriate changes.)
Admin
What the parent means, is that (in a OO language) you should have wrapped res1, etc. inside objects. That doesn't mean you have to wrap every function call, but at least the allocation/deallocation. That way they will get cleaned up properly without the goto's. There's always a way to do things more elegantly without goto's. Don't try to make excuses for using them.
Admin
No, that's fine. Well, not fine, but I can claim to have seen worse:
One night I was called out to fix a batch process that was failing. PL/I and CICS if it matters. Now, this was a system that was "inherited" and we weren't sure if we had up-to-date source for all of it. And, as luck would have it, the part that was breaking didn't.
Anyway. This particular piece of code had dynamic jumps implemented in PL/I, basically done through arrays of variables whose contents were pointers to routines. 2 levels of indirection, as it was bouncing stuff through 2 jump tables. And the contents of the arrays themselves changed dyamically. Oh yes. Completely fucking impossible to debug.
Imagine. 3 AM. Out of date source code. What code I had indicated massive WTFery. So I did what any sane person would do. hacked out the troublesome line in the input stream, kicked the process back off, and left it until daylight.
The problem turned out to not be a problem with the jump table stuff but instead a bounds overflow, the data we were failing on indicated a number of cocktail sticks ordered : by unit[1]. the resulting number was too big for the field in which it was to be contained - BLAM!
Simon
[1] Which seems to indicate that a certain chain of off-licenses in the UK can (or could) order single cocktail sticks from their suppliers
Admin
LABEL VARIABLE, that's what they were called in PL/I.
Simon
Admin
Those two 'valid' big goto examples are preferrable over a big list of nested ifs, but I believe a switch would be the better solution.
Somehow I feel the presence of goto in a high-level language defeats the purpose of features like while and for. If we start using goto in scripts, we might as well throw away all languages and train programmers to write machine code directly. Death to while!
Admin
Cool. But quite bad. When your SetDeviceParameter() raises BeerTooWarmException, you'll have a resource leak, which is not quite obvious.
But that's not a problem, for every programmer I know can immediately list all the exceptions any given operation raises in modern languages.
Admin
Arrgh... and methods like that should not be return type void. Return the device object or throw a checked exception, but don't return null.
Admin
But really, who uses C these days anyway?
Alsmot every Operating System and OS-level interface in existence? Hundreds of millions of lines of code across hundreds of systems.
Admin
And yet, no-one has written a high-performance OS in Java...! [;)]
Seriously, <FONT face="Courier New" size=2>goto</FONT>s are sometimes used in high-performance/RTOS kind of code, like kernels and drivers. When dealing with an environment where each instruction counts (like small embedded systems), your outlook changes than when doing average desktop or server development. Moreso when your outlook on enhancing performance is to just throw another blade in the server!
ASM has been using <FONT face="Courier New" size=2>goto</FONT> (in various forms) for years, and still does... They are not evil by themselves; like most things, it is the user that makes it evil.
Admin
The original "Goto Considered Harmful" article: http://www.acm.org/classics/oct95/
However, one legitimate (if infrequent) use of goto is to get out of more than one nested loop, as break/continue only get you out of the first one:
The goto-less solution to this problem needs an extra variable, and is arguably less readable:Admin
Some places still do. I know, I had to survive it here. Those 2 and a half weeks were a true pain in the arse.
Admin
Your solution uses extra variables for no reason. The goto code does the same thing, but with less memory. Maybe memory doesn't matter for your code, but sometimes it matters a lot. That's why OS kernels are still written in C, even today!
If you haven't personally needed to write code like that, then go ahead and don't use goto. Just don't extrapolate from "you" to "everybody."
Admin
i = 0;
j=0;
done = false;
while (i <N P !done){< &&>
while (j < N && !done){
//do stuff that might not need all the i,j combinations
j++;
}
i++;
}
no gotos, no extra variable, and maintains readability. IMO it improves readability over the goto version because all logic determining program flow is on two lines, the two while statements, rather than three, two for statements and a goto.
Admin
bah, that cut off the first while loop. That should be (i less-than N && !done)
Admin
The Linux kernel is a very precise (although huge) snippet of code that is both in C (meaning no exceptions) and in need of very high performances (meaning once again no exceptions even if they were avaible).
The kernel is NOT the rule, it's the exception, and it's built by highly educated people with high understanding of the language, it's features and their implications.
Not many people will ever submit a patch to the kernel itself, therefore is Alex's double barrier (you won't encounter many case where you need gotos and usually - but not always - these won't even be) perfectly valid and acceptable
No, from an efficiency point of view an exception (which is what is usually needed to replace a well used goto) is VERY expensive, codes requiring very high levels of performance (such as the aforementioned Linux kernel) can't run without gotos, because the performance hit would be as horrible as unjustified.
Now if you want to have fun, you may try rewriting the kernel in C++ using exceptions, but you won't ever get anywhere close the the C version's performances.
Admin
Personally, I consider exceptions an ugly kludge, as bad as poorly used gotos. They're effectively a COMEFROM statement.
When you write code like this:
try
you have no idea precisely what part of the code that may throw exceptions called by doSomethingRisky has triggered the flagError unless you have a unique exception for each failure. And even if you do, you end up with something every bit as nasty as directly calling gotos from the code under doSomethingRisky into labels in the position of the catch block.{
doSomethingRisky();
}
catch( BorkedException b )
{
flagError();
}
Everything you call from your function can potentially be an exit point, bypassing the function entirely. You want to clean up? Tough. Let's consider the doSomethingRisky() function in more depth.
void doSomethingRisky()
If getFileLock throws an exception, the thread resources never get deallocated. If doStuff throws an exception, the file remains locked and the thread resources are never deallocated. And even if it's unlockFile that fails, you won't get the chance to deallocate those thread resources.{
allocateThreadResources();
getFileLock();
doStuff();
unlockFile();
deallocateResources();
}
Worse, if it fails, it fails invisibly. There is no indication in this function whether the errors are being handled at some higher level or not. Looking at that code doesn't tell you if there's error handling or not; it's quite possible that every failure has its own exception that cleans up appropriately, but it's not visible at this level.
Personally I prefer error handling of the form:
Because error codes have to be visibly propagated up the function tree, you can tell at a glance whether a function has implemented error handling or not. If a function dies without achieving its aims, control returns to the function that called it and doesn't go to the exception code, and a simple test of the return value lets you know whether or not you have to clean up.int errorCode = doSomethingRisky();
switch( errorCode )
{
BAD_THING_ERROR:
flagBadThingError();
break;
...
}
But I'm not usually working with mission-critical code. If every function I was going to call had an unacceptable chance of failure and the need to clean up a heap of things after it, nesting conditionals to handle it this way would make the code hideous. Far better would be to adopt the Linux kernel modus operandi:
int doSomethingRisky()
{
if(!allocateThreadResources())
{
goto threadAllocateFailure;
}
if(!getFileLock())
{
goto fileLockFailure;
}
doStuff();
fileLockFailure:
unlockFile();
threadAllocateFailure:
deallocateThreadResources();
}
I hope this convinces some people at least that gotos have their place.
NB: this forum software is hideous :P
Admin
Quote
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.
While java doesn't have a goto, it does have a break which will take a label, and then goto that label, which to be honest is goto really in all but name (and the places where java lets you use it are the only places I ever use goto)
Admin
Heh... that's like saying += is ++ in all but name because you only ever += by 1 :)
Admin
I'm guessing that you are not aware of:
try {
// do something
} catch (Exception e) {
// somthing happened
} finally {
// always executes
}
In any event, your approach is not safe because it assumes you know everything that can go wrong. Specifically it makes a lot of assumptions that things won't go wrong.
Admin
Why do people insist on calling structured statements gotos? An 'if' is a goto really in all but name. Gotos allow you to jump into the middle of loops or if statements from completely unrelated blocks of code. There is no feature in Java that allows this.
Admin
Java has a keyword goto that is not allowed. Therefore there is no Java program with gotos. The bytecodes are like assembly of machine instructions. They have nothing to do with this discussion and I'm puzzled as to why you would think this was a relevant point.
Admin
Personally I think that is a really stupid stance. I've worked with a lot code like that and it's never reliable.
try/catch/finally
And how does a return code tell you that errors are being handled?
First, checked exceptions in Java are not invisible. You have to do something about them in your code.
Secondly, what happens to your code when someone adds a new return code? How about all the other places that you used this redundant piece of tedious code?