views:

1302

answers:

24
+19  Q: 

do...while vs while

Possible Duplicates:
While vs. Do While
When should I use do-while instead of while loops?

I've been programming for a while now (2 years work + 4.5 years degree + 1 year pre-college) and I've never used a do-while loop short of being forced to in the Introduction to Programming course. I have a growing feeling that I'm doing programming wrong if I never run into something so fundamental.

Could it be that I just haven't run into the correct circumstances?

What are some examples where it would be necessary to use a do-while instead of a while?

(My schooling was almost all in C/C++ and my work is in C#, so if there is another language where it absolutely makes sense because do-whiles work differently, then these questions don't really apply)

Edit: To clarify...I know the difference between a while and a do-while. While checks exit condition then performs tasks, do-while performs tasks then checks exit condition.

+21  A: 

If you always want the loop to execute at least once. It's not common, but I do use it from time to time. One case where you might want to use it is trying to access a resource that could require a retry, e.g.

do
{
   try to access resource...
   put up message box with retry option

} while (user says retry);
Bob Moore
So I guess this would follow under the "I haven't run into that circumstance."
mphair
honestly, i very rarely run into a circumstance when I just need to use a do..while..
Stan R.
Maybe a little short, but Bob is correct. Do/while should be used when you want to run the code block *at least one time*. You should use a while loop when you don't know if you even want to run it a single time. That said, I can tell you that with around 15 years of development experience, I've used many times more while loops than do/while loops.
consultutah
I've used them from time to time too, though rarely. After a bit they usually get refactored into a normal while loop as well - just because the areas around it changed and made a do...while more clumsy than it first was.
Joshua
I usually code my socket listening code in a `do..while` loop. Seems more appropriate. But beside that, I don't remember when I needed a `do..while` loop. I may be misguided, but anything streamed look better in a do loop.
Pierre-Alain Vigeant
It is fairly common. But I don't see why in your example you would not use a while loop. And I don't see why this answer is being upvoted.
anon
@Bob (post code update): would that not be the same as pSink = m_sslSinks.GetFirstSink();while(pSink){ //do stuff pSink = m_sslSinks.GetNextSink();}
mphair
ack, fell victim to the Stack Overflow demand for speed and threw something up as fast as possible from old code. It's not a good example, I'll delete it.
Bob Moore
@Bob, that example is actually more verbose than the while loop alternative.
consultutah
Useful to define macros, the best place I've used it
Ast Derek
Took the words out of my mouth. I've used the `do...while` a handful of times because I needed the loop to execute at least once no matter what.
Steve Wortham
+3  A: 

do while is if you want to run the code block at least once. while on the other hand won't always run depending on the criteria specified.

spinon
A: 

while loops check the condition before the loop, do...while loops check the condition after the loop. This is useful is you want to base the condition on side effects from the loop running or, like other posters said, if you want the loop to run at least once.

I understand where you're coming from, but the do-while is something that most use rarely, and I've never used myself. You're not doing it wrong.

You're not doing it wrong. That's like saying someone is doing it wrong because they've never used the byte primitive. It's just not that commonly used.

Rafe Kettler
+20  A: 

do-while is better if the compiler isn't competent at optimization. do-while has only a single conditional jump, as opposed to for and while which have a conditional jump and an unconditional jump. For CPUs which are pipelined and don't do branch prediction, this can make a big difference in the performance of a tight loop.

Also, since most compilers are smart enough to perform this optimization, all loops found in decompiled code will usually be do-while (if the decompiler even bothers to reconstruct loops from backward local gotos at all).

Ben Voigt
+1 for adding relevant technical information to the choice between loop forms.
qstarin
+1 I wonder if this is considered premature optimization
Josh Stodola
Not only premature but useless. If you really wanted a while loop i.e. the ability to iterate 0 times, you have to enclose the loop in an if which brings that jump back in.
JeremyP
@Jeremy: The jump you speak of is outside the loop, it isn't executed N times.
Ben Voigt
Consider also the classic use of do-while in Duff's device (wherein a while loop is transformed into an unrolled do-while with a larger step plus a jump table to handle the remainder) which dramatically reduces the loop overhead -- in applications such as memset, memcmp, memcpy it may increase throughput by a factor of 10.
Ben Voigt
+6  A: 

I used them a fair bit when I was in school, but not so much since.

In theory they are useful when you want the loop body to execute once before the exit condition check. The problem is that for the few instances where I don't want the check first, typically I want the exit check in the middle of the loop body rather than at the very end. In that case, I prefer to use the well-known for (;;) with an if (condition) exit; somewhere in the body.

In fact, if I'm a bit shaky on the loop exit condition, sometimes I find it useful to start writing the loop as a for (;;) {} with an exit statement where needed, and then when I'm done I can see if it can be "cleaned up" by moving initilizations, exit conditions, and/or increment code inside the for's parentheses.

T.E.D.
Out of curiosity...why "for(;;)" instead of "while(true)"?
mphair
Probably just taste. I've grown to equate `for(;;)` with "infinite loop", whereas `while(true)` I have to stop and think about. Perhaps its because I was coding C before there was a `true`. Back in the day we only had `TRUE` as a macro, and if something was buggy I'd have to go convince myself that the macro hasn't been redefined to `0` somehow (it happened!). With `for(;;)` there's no chance of that. If you insist on the while form, I'd almost rather see `while (1)`. Of course then some might wonder if it isn't the letter l...
T.E.D.
@T.E.D. - Heh, in my embedded programming class we just went with while(1). I think I'm wired a bit opposite of you. I have to stop and think about for(;;) but while(true)/while(1) is automatic. On a side note...I just noticed that you can exit code in comments...how is that?
mphair
@mphair - I assume you mean "edit code in comments". I'm still not sure if you are talking about the fact that I can edit comments I have already made, or that I put code blocks in the comments...
T.E.D.
@T.E.D. - I meant that I should `RTFM`. By "exit" I meant "make different than surrounding text".
mphair
@mphair: if you meant highlight and not "exit"... use backticks
smerlin
@mphair: Yeah, if you take note of the text that the editor puts in when you *italicize* or `codeify` text, you can just type that directly into the comment field yourself. I've seen some folks put in hyperlinks, but that's a bit too hardcore for me.
T.E.D.
@T.E.D.: My preferred notation for loop-until-explicit-exit is "do{}while(1);". Incidentally, in embedded systems work, my normal loop paradigm is "i=10; do {} while(--i);". For tight loops, that's much faster than a typical for(); I figure it's more readable to use that consistently as the loop pattern when an up-count isn't needed than to arbitrarily use for() in non-performance-critical cases.
supercat
Adding to the while(1) and for(;;) disusion, I've seen code using for(EVER) with EVER defined to be ;;
asr
@supercat - As I said, it's probably really just a matter of taste. I saw someone in another thread suggest `loop: ... goto loop`. They got voted up too. Ick.
T.E.D.
@asr: I think I'd prefer `#define FOREVER while(1)`, then you can take your pick of `do { } FOREVER;` and `FOREVER { }`
Ben Voigt
@TED, if you're worried about 1 looking like l, try `while(42)`.. ;-)
R..
@supercat: the only way that's faster than a "typical for" is if your compiler sucks. `for(i=10;i;i--)` should generate the same code and it's much more legible.
R..
@R..: The compiler I'm using uses "decfsz _i,f/goto loop" for a --i loop condition, and "decf _i,f/movf _i,w/btfss STATUS,Z/goto loop" for a separate decrement and test. Using a separate test also generates an extra "goto" from the start of the loop to the end. If you know any other compiler that's compatible with HT-PICC-18 but better, great. Otherwise, I do what works with my compiler.
supercat
+8  A: 

Do while is useful for when you want to execute something at least once. As for a good example for using do while vs. while, lets say you want to make the following: A calculator.

You could approach this by using a loop and checking after each calculation if the person wants to exit the program. Now you can probably assume that once the program is opened the person wants to do this at least once so you could do the following:

do
{
    //do calculator logic here
    //prompt user for continue here
} while(cont==true);//cont is short for continue
thyrgle
Actually, now that you mention it, any kind of console based menu driven interface would do well in a do...while loop as well. For example, prompting for options (one key at a time) and only exiting when they choose continue or quit.
Joshua
`continue` is a keyword ;D
trinithis
Atrinithis: Lol... I slipped up. Thanks for correcting me there.
thyrgle
+2  A: 

The answers so far summarize the general use for do-while. But the OP asked for an example, so here is one: Get user input. But the user's input may be invalid - so you ask for input, validate it, proceed if it's valid, otherwise repeat.

With do-while, you get the input while the input is not valid. With a regular while-loop, you get the input once, but if it's invalid, you get it again and again until it is valid. It's not hard to see that the former is shorter, more elegant, and simpler to maintain if the body of the loop grows more complex.

delnan
I think the reason I've never used them for this is I usually end up telling the user what was wrong with their input. Which means the conditional would be in the center of a loop and I would just `break` if the input is correct.
mphair
@mphair: Actually, for that sort of situation I might sometimes be more inclined to use a "do {} while(0);" loop, using "continue;" if the user's input is unacceptable. If there's only one problem and message, using "do {} while(1);" and "break;" works nicely, but if there are multiple reasons to demand re-entry, the "continue;" construct works out more nicely.
supercat
A: 

I've used a do while when I'm reading a sentinel value at the beginning of a file, but other than that, I don't think it's abnormal that this structure isn't too commonly used--do-whiles are really situational.

-- file --
5
Joe
Bob
Jake
Sarah
Sue

-- code --
int MAX;
int count = 0;
do {
MAX = a.readLine();
k[count] = a.readLine();
count++;
} while(count <= MAX)
danyim
A: 

I am programming about 12 years and only 3 months ago I have met a situation where it was really convenient to use do-while as one iteration was alwas necessary before checking a condition. So guess your big-time is ahead :).

Narek
Nearly everytime I've seen a do...while it was because of a lack of understanding of the problem and involved some terrible hack. There are exceptions, but *generally* speaking, if you've got a do...while, you should rethink what you're doing... :-)
Brian Knoblauch
If you where right then do-while would be excluded from all programming languages in order to not confuse programmers :).
Narek
+6  A: 

I have used this in a TryDeleteDirectory function. It was something like this

do
{
    try
    {
        DisableReadOnly(directory);
        directory.Delete(true);
    }
    catch (Exception)
    {
        retryDeleteDirectoryCount++;
    }
} while (Directory.Exists(fullPath) && retryDeleteDirectoryCount < 4);
Chandam
Nice. This is the first example that actually makes sense to be wrapped in a do...while.
Joshua
Indeed. I like this one.
mphair
Why/how is this better than a standard `while`?
Josh Stodola
The loop will always execute once, so you might want to do something, then try it again if it fails. If you use a normal while loop, you'll be checking if it fails before you've even done it on the first iteration.
SLC
I was about to post a new example using do-while wrapped around a MessageBox with a ID_RETRY return (which I've used more than once), but this illustrates the try-at-least-once approach OK.
Bob Moore
@SLC But wouldn't you want to check if the directory exists before-hand anyways?
Josh Stodola
@Josh In this example, yes. But if you were trying to open a connection to a busy server, you'd connect first, and see if the response was 'busy'. If it was, you'd try again a few times before giving up.
SLC
+4  A: 

A situation where you always need to run a piece of code once, and depending on its result, possibly more times. The same can be produced with a regular while loop as well.

rc = get_something();
while (rc == wrong_stuff)
{
    rc = get_something();
}

do
{
    rc = get_something();
}
while (rc == wrong_stuff);
Edward Leno
A: 

The most common scenario I run into where I use a do/while loop is in a little console program that runs based on some input and will repeat as many times as the user likes. Obviously it makes no sense for a console program to run no times; but beyond the first time it's up to the user -- hence do/while instead of just while.

This allows the user to try out a bunch of different inputs if desired.

do
{
   int input = GetInt("Enter any integer");
   // Do something with input.
}
while (GetBool("Go again?"));

I suspect that software developers use do/while less and less these days, now that practically every program under the sun has a GUI of some sort. It makes more sense with console apps, as there is a need to continually refresh the output to provide instructions or prompt the user with new information. With a GUI, in contrast, the text providing that information to the user can just sit on a form and never need to be repeated programmatically.

Dan Tao
A: 

It's as simple as that:

precondition vs postcondition

  • while (cond) {...} - precondition, it executes the code only after checking.
  • do {...} while (cond) - postcondition, code is executed at least once.

Now that you know the secret .. use them wisely :)

John Paul
Like I said, I know how they work, I just wasn't sure in what case one makes sense over the other.
mphair
It's logical that you use the do {} while when you know for sure that you have to pass at least once trough the loop. Like for instance if you have a function that finds an element in an array and you've previously put an if array.IsEmpty() then return; . If it passed that check you can safely use do {} while. do-while is also easy to think of, as a repetitive loop : "I eat until I'm satisfied" translates to do {eat();} while (!satisfied();). Testing the condition before the loop, is considered safer.. and that's why it's used more often.
John Paul
+1  A: 

I've used it for a reader that reads the same structure multiple times.

using(IDataReader reader = connection.ExecuteReader())
{
    do
    {
        while(reader.Read())
        {
            //Read record
        }
    } while(reader.NextResult());
}
Gordon Tucker
A: 

I use do-while loops all the time when reading in files. I work with a lot of text files that include comments in the header:

# some comments
# some more comments
column1 column2
  1.234   5.678
  9.012   3.456
    ...     ...

i'll use a do-while loop to read up to the "column1 column2" line so that I can look for the column of interest. Here's the pseudocode:

do {
    line = read_line();
} while ( line[0] == '#');
/* parse line */

Then I'll do a while loop to read through the rest of the file.

flies
Supporting comments anywhere in the file would be trivial (and simplify the code overall) if you just put `if (line[0]=='#') continue;` right after the `read_line` call in your main while loop...
R..
I can't see how I would implement your suggestion to find a header.(dang, can't figure out how to format code in the comments, plz help!) header = false; while (! header) { line = read_line(); if (line[0]=='#') continue; header = true; }this is clearer/simpler to you?
flies
A: 

Being a geezer programmer, many of my school programming projects used text menu driven interactions. Virtually all used something like the following logic for the main procedure:

do
    display options
    get choice
    perform action appropriate to choice
while choice is something other than exit

Since school days, I have found that I use the while loop more frequently.

GreenMatt
A: 

One of the applications I have seen it is in Oracle when we look at result sets.

Once you a have a result set, you first fetch from it (do) and from that point on.. check if the fetch returns an element or not (while element found..) .. The same might be applicable for any other "fetch-like" implementations.

Rajesh
+1  A: 

Here's my theory why most people (including me) prefer while(){} loops to do{}while(): A while(){} loop can easily be adapted to perform like a do..while() loop while the opposite is not true. A while loop is in a certain way "more general". Also programmers like easy to grasp patterns. A while loop says right at start what its invariant is and this is a nice thing.

Here's what I mean about the "more general" thing. Take this do..while loop:

do {
 A;
 if (condition) INV=false; 
 B;
} while(INV);

Transforming this in to a while loop is straightforward:

INV=true;
while(INV) {
 A;
 if (condition) INV=false; 
 B;
}

Now, we take a model while loop:

while(INV) {
     A;
     if (condition) INV=false; 
     B;
}

And transform this into a do..while loop, yields this monstrosity:

if (INV) {
 do
 {
         A;
         if (condition) INV=false; 
         B;

 } while(INV)
}

Now we have two checks on opposite ends and if the invariant changes you have to update it on two places. In a certain way do..while is like the specialized screwdrivers in the tool box which you never use, because the standard screwdriver does everything you need.

Luther Blissett
Replacing a "do {} while(x);" loop into a "while(x);" loop requires that X either be a condition that can be easily "primed", or that it be "naturally" true on the first pass. To me, priming statements before a loop imply that something within the loop needs priming, and a while(x) {};" loop implies that the loop may execute zero times. If I want a loop that will execute at least once, I use a "do {} while(x);" loop.
supercat
A: 

I 've used it in a function that returned the next character position in an utf-8 string:

char *next_utf8_character(const char *txt)
{
    if (!txt || *txt == '\0')
        return txt;

    do {
        txt++;
    } while (((signed char) *txt) < 0 && (((unsigned char) *txt) & 0xc0) == 0xc0)

    return (char *)txt;
}

Note that, this function is written from mind and not tested. The point is that you have to do the first step anyway and you have to do it before you can evaluate the condition.

quinmars
That's a nasty way of writing `*(unsigned char *)txt-0x80U<0x40`.
R..
A: 

Any sort of console input works well with do-while because you prompt the first time, and re-prompt whenever the input validation fails.

Lotus Notes
+1  A: 

I see that this question has been adequately answered, but would like to add this very relative specific use case scenario. You might start using do...while more frequently.

do
{
   ...
} while (0)

is often used for multi-line #defines. For example:

#define compute_values     \
   area = pi * r * r;      \
   volume = area * height

This works alright for:

r = 4;
h = 3;
compute_values;

-but- there is a gotcha for:

if (shape == circle)  compute_values;

as this expands to:

if (shape == circle) area = pi *r * r;
volume = area * h;

If you wrap it in a do ... while(0) loop it properly expands to a single block:

if (shape == circle)
  do
  {
    area = pi * r * r;
    volume = area * h;
  } while (0);
Brandon Horsley
+1  A: 

I can't imagine how you've gone this long without using a do...while loop.

There's one on another monitor right now and there are multiple such loops in that program. They're all of the form:

do { GetProspectiveResult(); } while (!ProspectIsGood());

Loren Pechtel
A: 

quite a common structure in a server/consumer

DOWHILE (no shutdown requested)
   determine timeout
   wait for work(timeout)
   IF (there is work)
      REPEAT
          process
      UNTIL(wait for work(0 timeout) indicates no work) 
      do what is supposed to be done at end of busy period. 
   ENDIF
ENDDO

the REPEAT UNTIL(cond) being a do {...} while(!cond)

Sometimes the wait for work(0) can be cheaper CPU wise (even eliminating the timeout calculation might be an improvement with very high arrival rates). Moreover, there are many queuing theory results that make the number served in a busy period an important statistic. (See for example Kleinrock - Vol 1)

Similarly:

DOWHILE (no shutdown requested)
   determine timeout
   wait for work(timeout)
   IF (there is work)
      set throttle
      REPEAT
          process
      UNTIL(--throttle<0 **OR** wait for work(0 timeout) indicates no work) 
   ENDIF
   check for and do other (perhaps polled) work. 
ENDDO

where check for and do other work may be exhorbitively expensive to put in the main loop or perhaps a kernel that does not support an efficient waitany(waitcontrol*,n) type operation or perhaps a situation where a prioritized queue might starve the other work and throttle is used as starvation control. This type of balancing can seem like a hack but it can be necessary. Blind use of thread pools would entirely defeat the performance benefits of the use of a caretaker thread with a private queue for a high updating rate complicated data structure as the use of a thread pool rather than a caretaker thread would require thread-safe implementation.

I really don't want to get into a debate about the pseudo code (eg whether shutdown requested should be tested in the UNTIL) or caretaker threads versus thread pools - this is just meant to give a flavor of a particular use case of the control flow structure.

pgast
+2  A: 

This is sort of an indirect answer, but this question got me thinking about the logic behind it, and I thought this might be worth sharing.

As everyone else has said, you use a do ... while loop when you want to execute the body at least once. But under what circumstances would you want to do that?

Well, the most obvious class of situations I can think of would be when the initial ("unprimed") value of the check condition is the same as when you want to exit. This means that you need to execute the loop body once to prime the condition to a non-exiting value, and then perform the actual repetition based on that condition. What with programmers being so lazy, someone decided to wrap this up in a control structure.

So for example, reading characters from a serial port with a timeout might take the form (in Python):

response = []
char_read = port.read(1)

while char_read:
    response.append(char_read)
    char_read = port.read(1)

# When there's nothing to read after 1s, there is no more data

''.join(char_read)

Note the duplication of code: char_read = port.read(1). If Python had a do ... while loop, I might have used:

do:
    char_read = port.read(1)
    response.append(char_read)
while char_read

The added benefit for languages that create a new scope for loops: char_read does not pollute the function namespace. But note also that there is a better way to do this, and that is by using Python's None value:

response = []
char_read = None

while char_read != '':
    char_read = port.read(1)
    response.append(char_read)

''.join(char_read)

So here's the crux of my point: in languages with nullable types, the situation initial_value == exit_value arises far less frequently, and that may be why you do not encounter it. I'm not saying it never happens, because there are still times when a function will return None to signify a valid condition. But in my hurried and briefly-considered opinion, this would happen a lot more if the languages you used did not allow for a value that signifies: this variable has not been initialised yet.

This is not perfect reasoning: in reality, now that null-values are common, they simply form one more element of the set of valid values a variable can take. But practically, programmers have a way to distinguish between a variable being in sensible state, which may include the loop exit state, and it being in an uninitialised state.

detly