• (cs)

    "Thankfully, the fellow responsible is 'no longer with us'"

    Is that because you stabbed him?

  • JB (unregistered)

    Maybe he didn't know about the "else" keyword...

  • (cs) in reply to pitchingchris
    pitchingchris:
    TheCPUWizard:
    GOTO may not be evil, but the "COMEFROM" statement (bonus points for the first person to identify the late 1970's language that had it) was pure evil.

    From what I'm reading, it was intended to be an april fools joke and never got removed.

    The Pick BASIC language has a 'RETURN TO' statement, which was not implemented as an April Fools joke. The reader of a Pick BASIC program could not assume that execution would return to the next statement after a GOSUB.

  • Jay (unregistered) in reply to Michael Cox
    Michael Cox:
    This looks like C++. Why not just use the goto keyword?

    Because GOTO is considered harmful, of course. Everyone knows you shouldn't use a GOTO in a modern program.

    That's why people who don't understand structured programming have to simulate GOTOs with bizarre and twisted applications of other statements.

    Seriously, though, this is my problem with people who insist on following a dogmatic rule without bothering to udnerstand why the rule was invented in the first place.

    Hierarchy of good code:

    Good: Clean structured code Bad: GOTOs Worse: Using other statements to simulate GOTOs and thus making the program even more difficult to understand than if you had just used a GOTO.

  • Mark (unregistered)

    I'm surprised how many people think the solution is to use multiple RETURNs. If you're really following structured programming rules (which is the only reason I can think you'd want to avoid GOTO), then your functions should have one unconditional RETURN at the very end.

    Dogma aside, function calls are more expensive than entering/exiting a loop. Maybe your compiler will fix that for you, but it won't fix that you're forcing someone reading the code to jump from place to place as they read in order to see what's going on. More functions isn't always better.

    Chains of conditionals are a tough problem. I've tried various solutions, depending on the language, and I generally don't like the options.

    If you really believe that sequences, conditions, and loops are the only things there are, then you can nest IF/ELSE after IF/ELSE... and I hope you have a nice, wide display terminal.

    I've toyed with

    if( StatementA && StatementB && StatementC ) { }

    but that's a bit of an abuse of short-circuit logic.

    IMO the only sane solution is to use named blocks if your language lets you BREAK from named blocks - after all, BREAK is nothing but a structured-programming compromise on the GOTO issue anyway; or to give up and use GOTO if your language won't let you use a break.

    I don't like using a loop as a named block just to get a BREAK, and I'm not sure this sequence of conditionals is long enough to require that kind of solution anyway, but it hardly seems WTF-worthy.

  • Stuck in the Tarpit (unregistered)

    In January I inherited code from someone who just left. It has a for-break loop like this that is 600 lines long. 600 lines of check-a-condition, set-an-error-variable and break.

    It made me twitchy just looking at it. I brought it up in the weekly team meeting and everyone 10 years younger than me said, "No, we like those." Now I feel twitchy and stabby (and get-off-my-lawny).

    Everyone accepts that it's wrong to have a function with multiple return points. Many code-scouring tools identify that as a problem. So, isn't multiple breaks within a loop wrong for the same reason? I'd much rather see:

    bool success = true;

    // Take 600 lines of crap and put it into separate condition-checker functions () if (success) success = checkConditionA ();

    if (success) success = checkConditionB (); etc..

    Thanks for listening to my rant. No one here will listen...

    Captcha: Saepius - and they said we couldn't create a human-Octopus hybrid!

  • Roberto (unregistered) in reply to Moshe

    As a matter of facts, "Code Complete" even suggest this trick.

  • Ryan (unregistered)

    Couldn't a switch(true) have accomplished the same thing?

  • (cs)

    You know, I've done that kind of stuff… in a do { } while(0); fortunately, and for a use case more complex than that. It's useful in C code in case you have multiple temporary objects/resources allocated in the scope, that you need to clean up, as then you cannot easily refactor to put the "loop" in its own function and replace the breaks by a function return. I feel it's a restricted case of goto that's clean, as all jump at the same point, without any possibility for a labyrinth of gotos.

  • averageGuy (unregistered) in reply to The Nerve
    The Nerve:
    bool bCreateModel = false;
    if (!pModel || asModelParts.GetSize() != asModelPartsToLoad.GetSize())
    {
        bCreateModel = true;        
    }
    

    for (UINT32 i = 0; i < asModelPartsToLoad.GetSize() && !bCreateModel; ++i) { if (asModelPartsToLoad[i] != asModelParts[i]) { bCreateModel = true;
    } }

    Fixed?

    Almost, but not quite.

    Your code would execute the for loop when the first condition was true. This would at least be wasteful and might lead to errors if !pModel meant that asModelPartsToLoad was not initialized.

    Putting an the for loop into an else clause would fix that.

  • (cs) in reply to Mark
    Mark:
    I'm surprised how many people think the solution is to use multiple RETURNs. If you're really following structured programming rules (which is the only reason I can think you'd want to avoid GOTO), then your functions should have one unconditional RETURN at the very end.

    Dogma aside, function calls are more expensive than entering/exiting a loop. Maybe your compiler will fix that for you, but it won't fix that you're forcing someone reading the code to jump from place to place as they read in order to see what's going on. More functions isn't always better.

    Chains of conditionals are a tough problem. I've tried various solutions, depending on the language, and I generally don't like the options.

    If you really believe that sequences, conditions, and loops are the only things there are, then you can nest IF/ELSE after IF/ELSE... and I hope you have a nice, wide display terminal.

    I've toyed with

    if( StatementA && StatementB && StatementC ) { }

    but that's a bit of an abuse of short-circuit logic.

    IMO the only sane solution is to use named blocks if your language lets you BREAK from named blocks - after all, BREAK is nothing but a structured-programming compromise on the GOTO issue anyway; or to give up and use GOTO if your language won't let you use a break.

    I don't like using a loop as a named block just to get a BREAK, and I'm not sure this sequence of conditionals is long enough to require that kind of solution anyway, but it hardly seems WTF-worthy.

    What's wrong with this?

        int loadSize = asModelPartsToLoad.GetSize();
    
        bool bCreateModel =(asModelParts.GetSize() != loadSize || 
                        !pModel);
    
        if(!bCreateModel )
        { 
            for (UINT32 i = 0; i < loadSize; ++i)
            {
                if (asModelPartsToLoad[i] != asModelParts[i])
                {
                    bCreateModel = true;           
                }
            }
        }
    
    
  • helix (unregistered)

    NOT a WTF, this is common for Embedded systems on small 8bit micro

  • mh (unregistered) in reply to Moshe
    Moshe:
    This is actually a pretty common coding convention. It is not an elaborate GOTO but a poor man exception handling.
    And there I was thinking that exception handling was nothing but an elaborate goto to begin with...
  • Ken B. (unregistered) in reply to TheCPUWizard
    TheCPUWizard:
    GOTO may not be evil, but the "COMEFROM" statement (bonus points for the first person to identify the late 1970's language that had it) was pure evil.
    I believe you are referring to INTERCAL?
  • Kruiser (unregistered)

    In C code, this is better than a case statement, especially for string operands, which are not supported.

  • Ken B. (unregistered) in reply to Kruiser
    Kruiser:
    In C code, this is better than a case statement, especially for string operands, which are not supported.
    Even better would have been "else".
  • IrishGuy (unregistered) in reply to TheCPUWizard
    TheCPUWizard:
    GOTO may not be evil, but the "COMEFROM" statement (bonus points for the first person to identify the late 1970's language that had it) was pure evil.

    It basically acted as a interceptor so that when the specified item was about to execute control would be transfered to the specified target, which could then decide if it was to return to the original statement or the one after it. Making things even more insane was the ability to have these in conditionals!

    As Ken B. mentioned it is INTERCAL. Although to be fair that language was designed to be as obtuse and evil as possible.

    For real world evil check out COBOL's "ALTER" statement.

  • Kruiser (unregistered) in reply to Ken B.

    If you use else (say 12 times, with some else if's) and later remove one condition; it gets complicated.

  • Larry (unregistered) in reply to Kruiser
    Kruiser:
    If you use else (say 12 times, with some else if's) and later remove one condition; it gets complicated.
    TRWTF is that you don't know how to use Perl:
    s/else if .*\{.*}//
    
  • fool (unregistered)

    Never heard of "else" ??

  • Xamuel (unregistered)

    Not seeing any real WTF here. The guy's code mirrors how he thinks about the process. To be honest, it's more readable than a lot of the alternatives offered up in the comments here.

  • EngleBart (unregistered)

    I skipped over all of the meme battles and trolling after the first 30 or so posts, so I do not know if anyone proposed this replacement yet. It eliminates the break at the end of the for loop. Forgetting that break is very dangerous as some other poster pointed out.

    This is clearly a better way to perform the same task. You could even create optional, self-documenting constants shown in angle brackets. Of course make sure that none of the constants are 0!

    bool bCreateModel = false;
    switch (0)
    {
    default:
    <case SEE_IF_IT_WAS_EVER_LOADED:>
        if (!pModel)
        {
            bCreateModel = true;
            break;
        }
    
    <case SEE_IF_THE_SIZES_ARE_THE_SAME:>
        if (asModelParts.GetSize() != asModelPartsToLoad.GetSize())
        {
            bCreateModel = true;
            break;
        }
    
    <case SAME_SIZE_BUT_ARE_THE_COMPONENTS_THE_SAME:>
        for (UINT32 i = 0; i < asModelPartsToLoad.GetSize(); ++i)
        {
            if (asModelPartsToLoad[i] != asModelParts[i])
            {
                bCreateModel = true;
                break;
            }
        }
    <case IF_I_GOT_HERE_I_DO_NOT_NEED_TO_DO_ANYTHING:>
    }
    
  • bah (unregistered) in reply to averageGuy

    I "I X'd your Y, pray I don't X any further"'d your post, pray I don't "I X'd your Y, pray I don't X any further" any further

    But seriously, in university, we were told that multiple returns from a function were okay. Not amazingly great, but better than the alternative of setting some variable, holding it above the water until the end and returning it. Unless it made more sense to do that.

    We weren't taught hard and fast rules on stuff like this, but we were encouraged to notice code smell, given on the complexity and natural form of the bit of code we were working on.

  • (cs) in reply to Michael Cox
    Michael Cox:
    This looks like C++. Why not just use the goto keyword?
    There are some good reasons for using goto command, but in this case just making a function that can return true or false, is probably better.
  • (cs)

    I found the problem- this line was meant to be a comment:

    for (;;)

    The code is designed to make you cry.

  • (cs) in reply to EngleBart
    EngleBart:
    I skipped over all of the meme battles and trolling after the first 30 or so posts, so I do not know if anyone proposed this replacement yet. It eliminates the break at the end of the for loop. Forgetting that break is very dangerous as some other poster pointed out.

    This is clearly a better way to perform the same task. You could even create optional, self-documenting constants shown in angle brackets. Of course make sure that none of the constants are 0!

    I don't like that, please!

    Maybe this way is better (although, this way uses goto, so if you want to use functions that return true/false you would do it differently):

    @ @<Check for create model@>= { bCreateModel=true; @<See if it was ever loaded@>; @<See if the sizes are the same@>; @<Same size, but are the components the same?@>; bCreateModel=false; yes_create_model: ; }

    @ @<See if it was ever loaded@>= { if(!pModel) goto yes_create_model; }

    @ @<See if the sizes are the same@>= { if(asModelParts.GetSize() != asModelPartsToLoad.GetSize()) goto yes_create_model; }

    @ @s UINT32 int @<Same size, but are the components the same?@>= { UINT32 i=asModelPartsToLoad.GetSize(); while(i--) { if (asModelPartsToLoad[i] != asModelParts[i]) goto yes_create_model; } }

  • (cs) in reply to Rick
    Rick:
    The Pick BASIC language has a 'RETURN TO' statement, which was not implemented as an April Fools joke. The reader of a Pick BASIC program could not assume that execution would return to the next statement after a GOSUB.
    Actually QBASIC (Microsoft BASIC) also allows RETURN to a different line number or line label, and I have used that feature, for a few different reasons. One was to simulate the effect of the INTERCAL command PLEASE RESUME #2
  • Greg (unregistered)

    TRWTF is that loops and functions are just syntactic sugar. That's why I like to use GOTO functions and push and pop all of my variables onto the stack manually.

  • wtf (unregistered) in reply to Greg
    Greg:
    TRWTF is that loops and functions are just syntactic sugar. That's why I like to use GOTO functions and push and pop all of my variables onto the stack manually.

    The real WTF is that you're using variables instead of just remembering where your data is and using the address.

  • Jimmy Hoffa (unregistered)

    Not a WTF. Union rules say that you must have at least 4 breaks per function. A for loop was the only way to fulfill this requirement.

  • Bert Glanstron (unregistered) in reply to Jimmy Hoffa
    Jimmy Hoffa:
    Not a WTF. Union rules say that you must have at least 4 breaks per function. A for loop was the only way to fulfill this requirement.
    Dear Jimmy Hoffa,

    In case you can’t tell, this is a dangerous place. The fact that you insist on trying to cheat the mafia clearly shows that you’re too dead and too missing to be organizing unions.

    Go away and rest in peace.

    Sincerely, Bert Glanstron

  • (cs)

    You will not use GOTO! Or else...!

  • PseudoNoise (unregistered)

    Hey, remember when the comments in TDWTF were less than 90% memes and talked about the code at hand?

    Good times .... good times...

    I vote for refactor into method suggested on the 1st page. I've seen code style guides that say "only have one return point from a function" but that's just proof those style guides need to die in a fire.

  • Java Expert (unregistered)

    Fixed for Java

    boolean bCreateModel = false;
    try
    {
        if (pModel != 0)
        {
            throw new RuntimeException();
        }
    
        if (asModelParts.size() != asModelPartsToLoad.size())
        {
            throw new RuntimeException();
        }
    
        for (int i = 0; i < asModelPartsToLoad.size(); ++i)
        {
            if (!asModelPartsToLoad.get(i).equals(asModelParts.get(i));
            {
                throw new RuntimeException();
            }
        }
    } catch (RuntimeException e) {
        bCreateModel = true;
    }
  • (cs) in reply to Rick
    Rick:
    pitchingchris:
    TheCPUWizard:
    GOTO may not be evil, but the "COMEFROM" statement (bonus points for the first person to identify the late 1970's language that had it) was pure evil.

    From what I'm reading, it was intended to be an april fools joke and never got removed.

    The Pick BASIC language has a 'RETURN TO' statement, which was not implemented as an April Fools joke. The reader of a Pick BASIC program could not assume that execution would return to the next statement after a GOSUB.
    That almost sounds like someone had heard about Continuation Passing Style and decided to try it in the worst way imaginable. Either that, or they were assembly programmers used to being able to munge the stack as they pleased, and missed being able to do it in HLLs. Either way, it's ugly, ugly, ugly... but then, Pick was pretty ugly in general from what little I recall of it.

  • (cs) in reply to mh
    mh:
    Moshe:
    This is actually a pretty common coding convention. It is not an elaborate GOTO but a poor man exception handling.
    And there I was thinking that exception handling was nothing but an elaborate goto to begin with...
    (Exceptions are 
                (a crutch) 
                (for (those 
                      who 
                      (can (not handle))) 
                     (first-class continuations)))
  • (cs)

    I don't know, but it seems like the point of the WTF is being missed here.

    One of my persistent habits is that of trying to find the general solution. (For example, trying to come up with something that kills everything from a flea to an elephant when what I really need is to just step on the cockroach of the moment.)

    I could see any of the above I guess, if there were thousands or even dozens of things to be checked in a logic sequence. (But then you probably need to refactor something a bit, right?)

    In this case, there are only 3 things to check, and no structured flow violations. So it seems to me that one possible good solution for this problem is:

    bool bCreateModel;
    if (!pModel)
    {
        bCreateModel = true;
    }
    else if (asModelParts.GetSize() != asModelPartsToLoad.GetSize())
    {
        bCreateModel = true;
    } 
    else
    {
        for (UINT32 i = 0; i < asModelPartsToLoad.GetSize(); ++i)
        {
            if (asModelPartsToLoad[i] != asModelParts[i])
            {
                bCreateModel = true;
                break;
            }
        }
    }
    
    

    Now isn't that nice and readable? Even if it isn't showy?

    Taking that into account, the original code author was "federalizing the simple": Used a wrecking ball to kill the cockroach. WTF!

  • Captain Normal Form (unregistered) in reply to Schol-R-LEA
    Schol-R-LEA:
    mh:
    Moshe:
    This is actually a pretty common coding convention. It is not an elaborate GOTO but a poor man exception handling.
    And there I was thinking that exception handling was nothing but an elaborate goto to begin with...
    (Exceptions are 
                (a crutch) 
                (for (those 
                      who 
                      (can (not handle))) 
                     (first-class continuations)))

    Continuations are too general for that task. Why embed a computation in a continuation monad (which brings in zero domain related methods, specifically because of how general it is) when you can embed it in an error monad (which brings in exception methods like try, catch, etc)?

  • (cs) in reply to v.dog
    v.dog:
    I found the problem- this line was meant to be a comment:

    for (;;)

    The code is designed to make you cry.

    It should have been:

    for (;;) {}

    That's the "do-nothing-forever" construct, a metaphor for so many things in this life.

  • (cs) in reply to Captain Normal Form
    Captain Normal Form:
    Schol-R-LEA:
    mh:
    Moshe:
    This is actually a pretty common coding convention. It is not an elaborate GOTO but a poor man exception handling.
    And there I was thinking that exception handling was nothing but an elaborate goto to begin with...
    (Exceptions are 
                (a crutch) 
                (for (those 
                      who 
                      (can (not handle))) 
                     (first-class continuations)))

    Continuations are too general for that task. Why embed a computation in a continuation monad (which brings in zero domain related methods, specifically because of how general it is) when you can embed it in an error monad (which brings in exception methods like try, catch, etc)?

    While I was being a bit silly, this actually is a very good point. Part of the reason continuations are difficult to use is because they are far too general and powerful a construct for everyday use. Like GOTO, they are both too primitive and too flexible to be used as is without lot of programmer discipline, and offer endless potential for mistakes and abuse. While I like continuations for the power they offer, in most cases they are better used as a primitive for some more restricted construct.

    OTOH, the fact remains that most programmers aren't familiar with continuations, or even the languages which support them. This is a shame, because they really are a fascinating construct, and (like many of the tools in functional programming) knowing about them changes you perspective on what things like expressions and functions really are.

  • (cs)

    I once had to implement an isEmpty() method in JavaScript, and the only way I could find to do it in constant time was

    for (item in this) { return false; } return true;

  • Matthew Chaboud (unregistered) in reply to Michael Cox

    One of the reasons to use a construct like this (though I've generally thought that do{}while(0) is cleaner) is that goto statements can't skip forward over initialization.

    So, if you want to localize your initializers so your code is both readable and easy to refactor, and you want to dodge having deep exit-out if blocks, a loop-based construct like this can be useful. Also remember that, in ANSI C++, goto was restricted to labels within the current block. No destructor-ness was accounted for.

    do{}while(0), while it still only lets you know that it's a faux-loop at the end, at least doesn't run the risk of turning into an infinite loop if you forget to put a break in the default clause. I typically prefer it to infinite for loops.

    Just put a comment at the top of the block indicating what you're up to and it's a pretty friggin' reasonable thing for anyone but a complete novice programmer.

  • Simon (unregistered)

    As others have said, do{...}while(0) would be better than for(;;), but this is really not a WTF. This sort of structure is fairly common. The main advantage is that your function has a single point of exit, which can make it much easier to debug. Since you know that every part of your function will cross that point regardless of what error may have occurred, you can use that to free up any memory which may have been allocated at that single point, which makes tracking down and fixing memory leaks much easier.

    Think of it as C's version of try & catch.

  • Troy (unregistered) in reply to averageGuy
    averageGuy:
    The Nerve:
    bool bCreateModel = false;
    if (!pModel || asModelParts.GetSize() != asModelPartsToLoad.GetSize())
    {
        bCreateModel = true;        
    }
    

    for (UINT32 i = 0; i < asModelPartsToLoad.GetSize() && !bCreateModel; ++i) { if (asModelPartsToLoad[i] != asModelParts[i]) { bCreateModel = true;
    } }

    Fixed?

    Almost, but not quite.

    Your code would execute the for loop when the first condition was true. This would at least be wasteful and might lead to errors if !pModel meant that asModelPartsToLoad was not initialized.

    Putting an the for loop into an else clause would fix that.

    I guess you didn't notice that !bCreateModel in the condition of the loop. It works, unless GetSize() has some unwanted side-effect. However, I don't understand why he just didn't make the loop the else clause of the if.

  • Supercoder (unregistered)

    Code is perfectly OK.

    It avoids unnecessary testing after bCreateModel has been set, and it skips the extra test which would be required to test if bCreateModel was set before each step.

    Since this is C++, it's a good rule of thumb to avoid gotos to transfer control between scopes, since any destructors that should have been run at the end of the scope won't be run.

    A do { } while(0) loop is preferable, but only because you don't need to remember the final break statement.

    Only WTF is blaming someone for writing bad code, because one is unfamiliar with this construct.

  • Lazy Evaluation is your friend (unregistered)
    
    bool bCreateModel = false;
    UINT32 i = 0;
    UINT32 j = 0;
    
    bCreateModel = !pModel || (j = asModelPartsToLoad.GetSize()) != asModelParts.GetSize();
    
    while(!bCreateModel && i < j)
    {
        bCreateModel = asModelPartsToLoad[i] != asModelParts[i];
        i++;
    }
    
    
  • Wyrdo (unregistered) in reply to JJ
    JJ:
    For everyone who has had the "GoTo is Evil" Kool-Aid forced down their throats, I'll repeat my mantra: "No language feature is evil. It is the misuse of a language feature that is evil."

    (In reality, I agree with you, but I have to go with the general meme of one-ups-manship and oh-yeah-ya-think-so here on the site.)

    Clearly you haven't seen INTERCAL. It's very hard to not misuse any of its "features".

    Furry cows moo and decompress.

  • Dennis Ritchie (unregistered) in reply to ais523
    ais523:
    I've actually done this with a do{}while(0) loop in C, because it was clearer than the alternatives. (This was generated code, btw; the generated version was meant to be readable, but the original was the bit you actually edited.) It's a nice paradigm for what would otherwise lead to 20 nested if statements.

    If you have C at your disposal, you can just use goto.

  • Coder (unregistered) in reply to TheCPUWizard
    TheCPUWizard:
    GOTO may not be evil, but the "COMEFROM" statement (bonus points for the first person to identify the late 1970's language that had it) was pure evil.

    It basically acted as a interceptor so that when the specified item was about to execute control would be transfered to the specified target, which could then decide if it was to return to the original statement or the one after it. Making things even more insane was the ability to have these in conditionals!

    I don't think you ever debugged an enterprise app written in DEC BASIC.

    1000 Every language that has a label or line-number 1010 that you can GOTO has a COMEFROM problem. It is 1020 not the GOTO that is the problem (although a 1030 computed GOTO is a bit of a problem). GOTO 1050 1040 OK, WHERE DID THIS LINE COME FROM ? 1050 It is the come-from that is the problem.

    Languages that have loop and control structures (structured programming languages) clarify how you get to each line. Structures where the conditional is implemented at the top are implicitly (GOTO 1040) COMEFROM structures. Despite what Wikepedia claims, this does not make them more difficult.

    Note: this comment has a bug.

  • Lisp Weenie (unregistered) in reply to dave
    dave:
    Java has the nice, largely unused feature of labeled blocks, which can be used in these cases (when you're too lazy extract the logic to another method).
    determineCreate: {
        if (!pModel)
        {
            bCreateModel = true;
            break determineCreate;
        }
        ...
    }
    

    Like all good programming language features, Lisp had it first and did it better:

    (block determine-create
       (unless p-model
           (setq create-model t)
           (return-from determine-create)) 
        ...)
    

    Not that it would actually be necessary to use this structure in Lisp, given that Lisp allows the following, much more elegant solution, which takes advantage of the built-in structural equality operator:

    (let ((create-model (or (not model)
                            (not (equalp model-parts model-parts-to-load)))))
       ;; create-model is defined correctly in only 2 LOC, bitch.
    )
    

    Captcha: odio, Spanish for "I hate". Odio Java.

Leave a comment on “Masquerading as a Loop”

Log In or post as a guest

Replying to comment #:

« Return to Article