Is while (true) with break bad programming practic

2020-01-24 11:56发布

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?

22条回答
老娘就宠你
2楼-- · 2020-01-24 12:25

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,

查看更多
再贱就再见
3楼-- · 2020-01-24 12:27

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.

查看更多
在下西门庆
4楼-- · 2020-01-24 12:28

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.

查看更多
劫难
5楼-- · 2020-01-24 12:30

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.

查看更多
Anthone
6楼-- · 2020-01-24 12:32

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.

查看更多
疯言疯语
7楼-- · 2020-01-24 12:33

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.
}
查看更多
登录 后发表回答