Let me share one of my favorite little programming idioms … do { … } while (false);

I picked it up from a friend who learned it from a friend, who probably saw it in a book. It may seem like a do-nothing, but it is a very nice low-budget and high performance exception handling mechanism. The typically application is something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// setup
int status = 0;

do {
   // preconditions
   status = doSomething();
   if (status) break;
   status = doSomethingElse();
   if (status) break;

   // computation
   status = doWhatYouWantedToInTheFirstPlace();
} while (false);

// cleanup
return status;

Without the DWF mechanism, the same code either requires either exceptions, duplicating cleanup code, or writing deeply nested if statements until all your preconditions are satisfied. Even though DWF initially may seem a little unorthodox, the code is actually very clear, readable, and maintainable.

21 Responses to “do { … } while (false);”

  • Noname:

    I do the same with a goto statement. Don’t freak out, you can use goto responsibly. You don’t need an extra variable, or a confusing do{…}while(false) statement. Everything unwinds nicely at the end of the function. It just works well, I probably wouldn’t use this do while thing at all. It’s functionally the same as the goto method and requires an extra variable, plus another control structure to interpret that variable.

  • Phil:

    You still need the status, unless you are going to put the calls in the if condition.

    status = DoSomething();
    if(!status)
    {
    status = DoSomethingElse();
    }
    if(!status)
    {
    status = DoWhatYouWantedToInTheFirstPlace();
    }

  • Abdul Habra:

    Another approach that I use is to break this into two methods. something like this:

    int m1() {
    int status = 0;
    // preconditions
    status = doSomething();
    if (status) return status;

    status = doSomethingElse();
    if (status) return status;

    // computation
    status = doWhatYouWantedToInTheFirstPlace();
    return status;
    }

    void m2() {
    int status= m1();
    if (status) {
    // cleanup
    }
    }

  • Rob Desbois:

    Have to say I dislike this syntax. If the status code was some sort of error at any point, an exception should be thrown if the language allows.

    If the language does not allow, or the status is not an error it would be far more appropriate to wrap the whole thing in a function and use return:

    function doTheThing()
    {
    // preconditions
    int status = doSomething();
    if (status)
    return status;

    status = doSomethingElse();
    if (status)
    return status;

    // computation
    return doWhatYouWantedToInTheFirstPlace();
    }

    It makes the exit points from the function far more readable, and reduces nesting.

  • Anonymous:

    Multiple exit points are a code smell. Code readability is more important, IMO, than heuristic performance enhancements.

  • Rob Desbois:

    #5: why only have one exit point? How is it more readable to keep track of return code through a whole function having to nest a lot of code just so the only return point is the last line of the function?

    IMHO the ‘flatter’ (i.e. less nested) a function is, the more readable it is. If the execution of line #3 of a 20 line function results in none of the rest of the function being executed, it is easier to read if it states that *explicitly* by using the ‘return’ keyword. It’s similar to the exception’s ‘fail-fast’ mechanism

    My opinion only, but I feel strongly on this one…out of interest why do you believe multiple exit points make a function more readable?

  • John DeHope:

    the code is actually very clear, readable, and maintainable. I disagree. You are using a loop as if it were a series of

    1
    if

    statements. That’s clear to you? As anonymous said, multiple exit points are always a sign that you need to think twice.

    1
    If-else

    statements are not your enemy, there is no reason to avoid them. If you are writing branching code, then avoiding them seems pathological to me. That’s why they exist!

  • Another way of doing that would be like this:

    boolean status = true;
    status &= doSomething();
    status &= doSomethingElse();
    status &= doWhatYouWantedToInTheFirstPlace();
    return status;

    (Works for Java anyway, my memory of C logic operators is a little hazy)

  • Rob Desbois:

    John I agree that the code is readable and maintainable, and I understand the reasoning behind the usage of the loop, but I disagree that multiple exit points are inherently bad – can you given a reason why?

    If the condition on line X of a function being true prevents the remainder of the function from being executed and causes ‘3′ to be returned, it should read like that:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    int f()
    {
       int status = 0;
       if (condition1)
          status = 1;
       else if (condition2)
          status = 2;
       else
          status = f2();

       return status;
    }


    int g()
    {
       if (condition1)
          return 1;

       if (condition2)
          return 2;

       return f2();
    }

    The second function clearly shows that condition1 being true results in 1 being returned and no more code being executed.
    To obtain the same insight into the first function you must read through the if..else.. structure, and check any code after it – simple in these contrived examples but in real code it can be harder.

    Now, if we are in an environment where RAII cannot easily be applied – e.g. C – then continuing through the function until cleanup is necessary, but the second example shows far more easily what it is than the first.

  • The reason that multiple exit points can be a problem goes back to the original assumptions: that there is cleanup code that needs to be executed before returning. Yes, you could cut and paste the cleanup code. I’ve seen plenty of code like that and plenty of bugs and memory leaks that stemmed from inconsistent cleanup paths.

  • Kohei Yoshida:

    I would love to start using this idiom to replace code that looks like this:

    http://go-oo.org/lxr/source/sc/sc/source/filter/xml/xmlimprt.cxx#2540

    In the code base I now work on, there is a plenty of over-nested if-statement blocks like this one above. In fact, that one is not bad in comparison to some of the worse ones I’ve encountered.

    Thanks for the good piece, Dennis!

  • Welcome to “C” programming.

    The standard macro is illustrated in http://en.wikipedia.org/wiki/C_preprocessor#Multiple_statements and widely used in well-written macros.

  • Kevin:

    You could always use labeled breaks –
    out: {
    status = doSomething();
    if (status) break out;
    status = doSomethingElse();
    if (status) break out;

    status = doWhatYouWant();
    }

  • jc:

    Terrible, terrible, premature optimization.

    Please… you really want to mess with stable and understood ideas such as exception handling? I’ve written this same code in C many many years ago, and I dont believe there’s a compelling reason to go back (even if it is to save a few cpu cycles).

  • jc:

    Hah… saw this on dzone and just assumed it was java code. If this is C… then more power to ya.

    Just dont be doing this in C# and Java! =)

  • lovely tricks, and make code more cleaner instead of the horrible nested if, thanks for sharing

  • Dave:

    I believe I first encountered the do{/*…*/}while(0) construct here:
    http://c-faq.com/cpp/multistmt.html

  • Phil:

    Some of you are addressing an error handling arrangement (IMO misguided) as if it were a preprocessor construct that makes multi-line macros safe for all invocations(IMO very useful, although I don’t like multi-line macros unless I really have no choice due to the language). They are two very different applications of a construct that appears on the surface to be the same thing.

  • neil:

    if(dofirst() && dosecond() && dolast(){}

    hmm
    one line
    no status variable
    same result

  • neil:

    if(dofirst() && dosecond() && dolast(){}

  • steve:

    This is substituting do-while for goto. Just use goto and be done with it.

Leave a Reply

Archives
Feeds
Book

slickedit_book.gif