views:

2303

answers:

21

I often use this code pattern:

while(true) {

    //do something

    if(<some condition>) {
     break;
    }

}

Another programmer told me that this was bad practice and that I should replace it with the more standard:

while(!<some condition>) {

    //do something

}

His reasoning was that you could "forget the break" too easily and have an endless loop. I told him that in the second example you could just as easily put in a condition which never returned true and so just as easily have an endless loop, so both are equally valid practices.

Further, I often prefer the former as it makes the code easier to read when you have multiple break points, i.e. multiple conditions which get out of the loop.

Can anyone enrichen this argument by adding evidence for one side or the other?

+3  A: 

The first is OK if there are many ways to break from the loop, or if the break condition cannot be expressed easily at the top of the loop (for example, the content of the loop needs to run halfway but the other half must not run, on the last iteration).

But if you can avoid it, you should, because programming should be about writing very complex things in the most obvious way possible, while also implementing features correctly and performantly. That's why your friend is, in the general case, correct. Your friend's way of writing loop constructs is much more obvious (assuming the conditions described in the preceding paragraph do not obtain).

Justice
+1  A: 

It depends on what you’re trying to do, but in general I prefer putting the conditional in the while.

  • It’s simpler, since you don't need another test in the code.
  • It’s easier to read, since you don’t have to go hunting for a break inside the loop.
  • You’re reinventing the wheel. The whole point of while is to do something as long as a test is true. Why subvert that by putting the break condition somewhere else?

I’d use a while(true) loop if I was writing a daemon or other process that should run until it gets killed.

ieure
A: 

He is probably correct.

Functionally the two can be identical.

However, for readability and understanding program flow, the while(condition) is better. The break smacks more of a goto of sorts. The while (condition) is very clear on the conditions which continue the loop, etc. That doesn't mean break is wrong, just can be less readable.

Doug T.
+18  A: 

There is a discrepancy between the two examples. The first will execute the "do something" at least once every time even if the statement is never true. The second will only "do something" when the statement evaluates to true.

I think what you are looking for is a DO LOOP. I 100% agree that while (true) is not a good idea because it makes it hard to maintain this code and the way you are escaping the loop is very "goto"esque which is considered bad practice.

Try:

do
{
    //do something
} while (!something);

Check your individual language documentation for the exact syntax. But look at this code, it basically does what is in the do, then checks the while portion to see if it should do it again.

Hopefully that makes sense...

Andrew G. Johnson
I often use while(true) for worker threads in services... only returning in the case of an thread abort exception...
Tracker1
I think he he means something on lines of var = truewhile (var) { if (somecondition) var = false; }
Nikron
Nikron, clearly he doesn't mean that as he gave examples using "break;"
Andrew G. Johnson
This answer fails to take into account the far more common idiom: while (true) { /* do something */ if (condition) break; /* do more something */ } This avoid duplicating the "do something" part: /* do something */ while (condition) { /* do more something */ /* do something */ }
jmucchiello
A: 

A few advantages of using the latter construct that come to my mind:

  • it's easier to understand what the loop is doing without looking for breaks in the loop's code.

  • if you don't use other breaks in the loop code, there's only one exit point in your loop and that's the while() condition.

  • generally ends up being less code, which adds to readability.

codelogic
A: 

I prefer the while(!) approach because it more clearly and immediately conveys the intent of the loop.

Jeremy Wilde
+7  A: 

I prefer

while(!<some condition>) {
    //do something
}

but I think it's more a matter of readability, rather than the potential to "forget the break." I think that forgetting the break is a rather weak argument, as that would be a bug and you'd find and fix it right away.

The argument I have against using a break to get out of an endless loop is that you're essentially using the break statement as a goto. I'm not religiously against using goto (if the language supports it, it's fair game), but I do try to replace it if there's a more readable alternative.

In the case of many break points I would replace them with

while( !<some condition> ||
       !<some other condition> ||
       !<something completely different> ) {
    //do something
}

Consolidating all of the stop conditions this way makes it a lot easier to see what's going to end this loop. break statements could be sprinkled around, and that's anything but readable.

Bill the Lizard
or if you find many ORs clumsy, you can define a function we_are_good() { return cond1 || cond2 || cond3; } local to the compilation unit and use that predicate function as the loop condition.
wilhelmtell
I usually only pull them out into a function if I'm going to use the function more than once, but that's a matter of my own personal preference. Readability is a perfectly good reason to do it, too.
Bill the Lizard
+1  A: 

If there's one (and only one) non-exceptional break condition, putting that condition directly into the control-flow construct (the while) is preferable. Seeing while(true) { ... } makes me as a code-reader think that there's no simple way to enumerate the break conditions and makes me think "look carefully at this and think about carefully about the break conditions (what is set before them in the current loop and what might have been set in the previous loop)"

In short, I'm with your colleague in the simplest case, but while(true){ ... } is not uncommon.

Larry OBrien
+2  A: 

while (true) might make sense if you have many statements and you want to stop if any fail

 while (true) {
     if (!function1() ) return;   
     if (!function2() ) return;   
     if (!function3() ) return;   
     if (!function4() ) return;  
   }

is better than

 while (!fail) {
     if (!fail) {
       fail = function1()
     }           
     if (!fail) {
       fail = function2()
     }  
     ........

   }
Martin Beckett
Yes, this is exactly my experience. I think the former is easier to read.
Edward Tanguay
On my university I had one teacher who told me that is was absolutely evil to do more than one return statements in a function. You should put your result in a variable (for instance called result) and return it at the end. Of course I didn't listen...
Roalt
@Roalt - see http://stackoverflow.com/questions/36707/should-a-function-have-only-one-return-statement
Daniel Earwicker
Thomas Eyde
The while(true) multiple exits does let you put other code between the function calls.
Martin Beckett
+6  A: 

When you can write your code in the form

while (condition) { ... }

or

while (!condition) { ... }

with no exits (break, continue, or goto) in the body, that form is preferred, because someone can read the code and understand the termination condition just by looking at the header. That's good.

But lots of loops don't fit this model, and the infinite loop with explicit exit(s) in the middle is an honorable model. (Loops with continue are usually harder to understand than loops with break.) If you want some evidence or authority to cite, look no further than Don Knuth's famous paper on Structured Programming with Goto Statements; you will find all the examples, arguments, and explanations you could want.

A minor point of idiom: writing while (true) { ... } brands you as an old Pascal programmer or perhaps these days a Java programmer. If you are writing in C or C++, the preferred idiom is

for (;;) { ... }

There's no good reason for this, but you should write it this way because this is the way C programmers expect to see it.

Norman Ramsey
i've never met any C programmer that prefers for(;;;){} over while(1){}
Javier
If I recall correctly, K;){} over while(1){}
Windows programmer
I think the reason for(;;) { } is used instead of while is because it comes closer to saying "forever"
Roalt
#define ever (;;)
Windows programmer
i think it's more readable to #define EVER ;; then you say for(EVER) and that makes it clearer that it's a for statement and EVER is a define.
Its me
Personally, I prefer while(1), and I've never used Pascal.@Its me, @Windows programmer: and it makes you have to look up what that define is in order to be sure what that code does.I suggest #define FOREVER for (;;) { — that way, you can break the editor's brace matching, too.
derobert
+1  A: 

The perfect consultant's answer: it depends. Most cases, the right thing to do is either use a while loop

while (condition is true ) {
    // do something
}

or a "repeat until" which is done in a C-like language with

do {
    // do something
} while ( condition is true);

If either of these cases works, use them.

Sometimes, like in the inner loop of a server, you really mean that a program should keep going until something external interrupts it. (Consider, eg, an httpd daemon -- it isn't going to stop unless it crashes or it's stopped by a shutdown.)

THEN AND ONLY THEN use a while(1):

while(1) {
   accept connection
   fork child process
}

Final case is the rare occasion where you want to do some part of the function before terminating. In that case, use:

while(1) { // or for(;;)
   // do some stuff
   if (condition met) break;
   // otherwise do more stuff.
}
Charlie Martin
A: 

There has been much talk about readability here and its very well constructed but as with all loops that are not fixed in size (ie. do while and while) you run at a risk.

His reasoning was that you could "forget the break" too easily and have an endless loop.

Within a while loop you are in fact asking for a process that runs indefinitely unless something happens, and if that something does not happen within a certain parameter, you will get exactly what you wanted... an endless loop.

Ólafur Waage
A: 

I think the benefit of using "while(true)" is probably to let multiple exit condition easier to write especially if these exit condition has to appear in different location within the code block. However, for me, it could be chaotic when I have to dry-run the code to see how the code interacts.

Personally I will try to avoid while(true). The reason is that whenever I look back at the code written previously, I usually find that I need to figure out when it runs/terminates more than what it actually does. Therefore, having to locate the "breaks" first is a bit troublesome for me.

If there is a need for multiple exit condition, I tend to refactor the condition determining logic into a separate function so that the loop block looks clean and easier to understand.

Conrad
+17  A: 

To quote that noted developer of days gone by, Wordsworth:

...
In truth the prison, unto which we doom
Ourselves, no prison is; and hence for me,
In sundry moods, 'twas pastime to be bound
Within the Sonnet's scanty plot of ground;
Pleased if some souls (for such their needs must be)
Who have felt the weight of too much liberty,
Should find brief solace there, as I have found.

Wordsworth accepted the strict requirements of the sonnet as a liberating frame, rather than as a straightjacket. I'd suggest that the heart of "structured programming" is about giving up the freedom to build arbitrarily-complex flow graphs in favor of a liberating ease of understanding.

I freely agree that sometimes an early exit is the simplest way to express an action. However, my experience has been that when I force myself to use the simplest possible control structures (and really think about designing within those constraints), I most often find that the result is simpler, clearer code. The drawback with

while (true) {
    action0;
    if (test0) break;
    action1;
}

is that it's easy to let action0 and action1 become larger and larger chunks of code, or to add "just one more" test-break-action sequence, until it becomes difficult to point to a specific line and answer the question, "What conditions do I know hold at this point?" So, without making rules for other programmers, I try to avoid the while (true) {...} idiom in my own code whenever possible.

joel.neely
i disagree on the specific point (i think while(true){} is a more 'pure' construct than while(condition){}); but i love the idea of "strict requirements as a liberating fame"
Javier
@joel: What a great answer! @Javier: goto is as pure as you can get, but generally you're better off picking something more restrictive and descriptive.
Shog9
+1  A: 

There's a substantially identical question already in SO at Is WHILE TRUE…BREAK…END WHILE a good design?. @Glomek answered (in an underrated post):

Sometimes it's very good design. See Structured Programing With Goto Statements by Donald Knuth for some examples. I use this basic idea often for loops that run "n and a half times," especially read/process loops. However, I generally try to have only one break statement. This makes it easier to reason about the state of the program after the loop terminates.

Somewhat later, I responded with the related, and also woefully underrated, comment (in part because I didn't notice Glomek's the first time round, I think):

One fascinating article is Knuth's "Structured Programming with go to Statements" from 1974 (available in his book 'Literate Programming', and probably elsewhere too). It discusses, amongst other things, controlled ways of breaking out of loops, and (not using the term) the loop-and-a-half statement.

Ada also provides looping constructs, including

loopname:
    loop
        ...
        exit loopname when ...condition...;
        ...
    end loop loopname;

The original question's code is similar to this in intent.

One difference between the referenced SO item and this is the 'final break'; that is a single-shot loop which uses break to exit the loop early. There have been questions on whether that is a good style too - I don't have the cross-reference at hand.

Jonathan Leffler
A: 

No, that's not bad since you may not always know the exit condition when you setup the loop or may have multiple exit conditions. However it does require more care to prevent an infinite loop.

mcrute
A: 

What your friend recommend is different from what you did. Your own code is more akin to

do{
    // do something
}while(!<some condition>);

which always run the loop at least once, regardless of the condition.

But there are times breaks are perfectly okay, as mentioned by others. In response to your friend's worry of "forget the break", I often write in the following form:

while(true){
    // do something
if(<some condition>) break;
    // continue do something
}

By good indentation, the break point is clear to first time reader of the code, look as structural as codes which break at the beginning or bottom of a loop.

billyswong
A: 

Sometime you need infinite loop, for example listening on port or waiting for connection.

So while(true)... should not categorized as good or bad, let situation decide what to use

JRomio
+2  A: 

It's not so much the while(true) part that's bad, but the fact that you have to break or goto out of it that is the problem. break and goto are not really acceptable methods of flow control.

I also don't really see the point. Even in something that loops through the entire duration of a program, you can at least have like a boolean called Quit or something that you set to true to get out of the loop properly in a loop like while(!Quit)... Not just calling break at some arbitrary point and jumping out,

PhoenixRedeemer
+1  A: 

Javier made an interesting comment on my earlier answer (the one quoting Wordsworth):

I think while(true){} is a more 'pure' construct than while(condition){}.

and I couldn't respond adequately in 300 characters (sorry!)

In my teaching and mentoring, I've informally defined "complexity" as "How much of the rest of the code I need to have in my head to be able to understand this single line or expression?" The more stuff I have to bear in mind, the more complex the code is. The more the code tells me explicitly, the less complex.

So, with the goal of reducing complexity, let me reply to Javier in terms of completeness and strength rather than purity.

I think of this code fragment:

while (c1) {
    // p1
    a1;
    // p2
    ...
    // pz
    az;
}

as expressing two things simultaneously:

  1. the (entire) body will be repeated as long as c1 remains true, and
  2. at point 1, where a1 is performed, c1 is guaranteed to hold.

The difference is one of perspective; the first of these has to do with the outer, dynamic behavior of the entire loop in general, while the second is useful to understanding the inner, static guarantee which I can count on while thinking about a1 in particular. Of course the net effect of a1 may invalidate c1, requiring that I think harder about what I can count on at point 2, etc.

Let's put a specific (tiny) example in place to think about the condition and first action:

while (index < length(someString)) {
    // p1
    char c = someString.charAt(index++);
    // p2
    ...
}

The "outer" issue is that the loop is clearly doing something within someString that can only be done as long as index is positioned in the someString. This sets up an expectation that we'll be modifying either index or someString within the body (at a location and manner not known until I examine the body) so that termination eventually occurs. That gives me both context and expectation for thinking about the body.

The "inner" issue is that we're guaranteed that the action following point 1 will be legal, so while reading the code at point 2 I can think about what is being done with a char value I know has been legally obtained. (We can't even evaluate the condition if someString is a null ref, but I'm also assuming we've guarded against that in the context around this example!)

In contrast, a loop of the form:

while (true) {
    // p1
    a1;
    // p2
    ...
}

lets me down on both issues. At the outer level, I am left wondering whether this means that I really should expect this loop to cycle forever (e.g. the main event dispatch loop of an operating system), or whether there's something else going on. This gives me neither an explicit context for reading the body, nor an expectation of what constitutes progress toward (uncertain) termination.

At the inner level, I have absolutely no explicit guarantee about any circumstances that may hold at point 1. The condition true, which is of course true everywhere, is the weakest possible statement about what we can know at any point in the program. Understanding the preconditions of an action are very valuable information when trying to think about what the action accomplishes!

So, I suggest that the while (true) ... idiom is much more incomplete and weak, and therefore more complex, than while (c1) ... according to the logic I've described above.

joel.neely
A: 

using loops like

while(1) { do stuff }

is necessary in some situations. If you do any embedded systems programming (think microcontrollers like PICs, MSP430, and DSP programming) then almost all your code will be in a while(1) loop. When coding for DSPs sometimes you just need a while(1){} and the rest of the code is an interrupt service routine (ISR).

devin