Are "while(true)" loops so bad?
Solution 1
I wouldn't say it's bad - but equally I would normally at least look for an alternative.
In situations where it's the first thing I write, I almost always at least try to refactor it into something clearer. Sometimes it can't be helped (or the alternative is to have a bool
variable which does nothing meaningful except indicate the end of the loop, less clearly than a break
statement) but it's worth at least trying.
As an example of where it's clearer to use break
than a flag, consider:
while (true)
{
doStuffNeededAtStartOfLoop();
int input = getSomeInput();
if (testCondition(input))
{
break;
}
actOnInput(input);
}
Now let's force it to use a flag:
boolean running = true;
while (running)
{
doStuffNeededAtStartOfLoop();
int input = getSomeInput();
if (testCondition(input))
{
running = false;
}
else
{
actOnInput(input);
}
}
I view the latter as more complicated to read: it's got an extra else
block, the actOnInput
is more indented, and if you're trying to work out what happens when testCondition
returns true
, you need to look carefully through the rest of the block to check that there isn't something after the else
block which would occur whether running
has been set to false
or not.
The break
statement communicates the intent more clearly, and lets the rest of the block get on with what it needs to do without worrying about earlier conditions.
Note that this is exactly the same sort of argument that people have about multiple return statements in a method. For example, if I can work out the result of a method within the first few lines (e.g. because some input is null, or empty, or zero) I find it clearer to return that answer directly than to have a variable to store the result, then a whole block of other code, and finally a return
statement.
Solution 2
AFAIK nothing, really. Teachers are just allergic to goto
, because they heard somewhere it's really bad. Otherwise you would just write:
bool guard = true;
do
{
getInput();
if (something)
guard = false;
} while (guard)
Which is almost the same thing.
Maybe this is cleaner (because all the looping info is contained at the top of the block):
for (bool endLoop = false; !endLoop;)
{
}
Solution 3
Douglas Crockford had a remark about how he wished JavaScript contained a loop
structure:
loop
{
...code...
}
And I don't think Java would be any worse for having a loop
structure either.
There's nothing inherently wrong with while(true)
loops, but there is a tendency for teachers to discourage them. From the teaching perspective, it's very easy to have students create endless loops and not understand why the loop isn't ever escaped.
But what they rarely mention is that all looping mechanisms can be replicated with while(true)
loops.
while( a() )
{
fn();
}
is the same as
loop
{
if ( !a() ) break;
fn();
}
and
do
{
fn();
} while( a() );
is the same as:
loop
{
fn();
if ( !a() ) break;
}
and
for ( a(); b(); c() )
{
fn();
}
is the same as:
a();
loop
{
if ( !b() ) break;
fn();
c();
}
As long as you can set up your loops in a way that works the construct that you choose to use is unimportant. If it happens to fit in a for
loop, use a for
loop.
One last part: keep your loops simple. If there's a lot of functionality that needs to happen on every iteration, put it in a function. You can always optimize it after you've got it working.
Solution 4
Back in 1967, Edgar Dijkstra wrote an article in a trade magazine about why goto should be eliminated from high level languages to improve code quality. A whole programming paradigm called "structured programming" came out of this, though certainly not everyone agrees that goto automatically means bad code.
The crux of structured programming is essentially that the structure of the code should determine its flow rather than having gotos or breaks or continues to determine flow, wherever possible. Similiarly, having multiple entry and exit points to a loop or function are also discouraged in that paradigm.
Obviously this is not the only programming paradigm, but often it can be easily applied to other paradigms like object oriented programming (ala Java).
Your teachers has probably been taught, and is trying to teach your class that we would best avoid "spaghetti code" by making sure our code is structured, and following the implied rules of structured programming.
While there is nothing inherently "wrong" with an implementation that uses break, some consider it significantly easier to read code where the condition for the loop is explicitly specified within the while() condition, and eliminates some possibilities of being overly tricky. There are definitely pitfalls to using a while(true) condition that seem to pop up frequently in code by novice programmers, such as the risk of accidentally creating an infinite loop, or making code that is hard to read or unnecessarily confusing.
Ironically, exception handling is an area where deviation from structured programming will certainly come up and be expected as you get further into programming in Java.
It is also possible your instructor may have expected you to demonstrate your ability to use a particular loop structure or syntax being taught in that chapter or lesson of your text, and while the code you wrote is functionally equivalent, you may not have been demonstrating the particular skill you were supposed to be learning in that lesson.
Solution 5
The ususal Java convention for reading input is:
import java.io.*;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String strLine;
while ((strLine = br.readLine()) != null) {
// do something with the line
}
And the usual C++ convention for reading input is:
#include <iostream>
#include <string>
std::string data;
while(std::readline(std::cin, data)) {
// do something with the line
}
And in C, it's
#include <stdio.h>
char* buffer = NULL;
size_t buffer_size;
size_t size_read;
while( (size_read = getline(&buffer, &buffer_size, stdin)) != -1 ){
// do something with the line
}
free(buffer);
or if you're convinced you know how long the longest line of text in your file is, you can do
#include <stdio.h>
char buffer[BUF_SIZE];
while (fgets(buffer, BUF_SIZE, stdin)) {
//do something with the line
}
If you're testing to see whether your user entered a quit
command, it's easy to extend any of these 3 loop structures. I'll do it in Java for you:
import java.io.*;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = br.readLine()) != null && !line.equals("quit") ) {
// do something with the line
}
So, while there certainly are cases where break
or goto
is justified, if all you're doing is reading from a file or the console line by line, then you shouldn't need a while (true)
loop to accomplish it -- your programming language has already supplied you with an appropriate idiom for using the input command as the loop condition.
Related videos on Youtube
JHarnach
Programmer / PC Gamer / Musician / Filmmaker / Tinker / Tailor / Soldier / Spy
Updated on December 04, 2020Comments
-
JHarnach over 3 years
I've been programming in Java for several years now, but I just recently returned to school to get a formal degree. I was quite surprised to learn that, on my last assignment, I lost points for using a loop like the one below.
do{ //get some input. //if the input meets my conditions, break; //Otherwise ask again. } while(true)
Now for my test I'm just scanning for some console input, but I was told that this kind of loop is discouraged because using
break
is akin togoto
, we just don't do it.I understand fully the pitfalls of
goto
and its Java cousinbreak:label
, and I have the good sense not to use them. I also realize that a more complete program would provide some other means of escape, say for instance to just end the program, but that wasn't a reason my professor cited, so...What's wrong with
do-while(true)
?-
JHarnach almost 13 yearsI dunno if the homework tag applies, I meant it more as a question of general programming, but I'll take it.
-
Chris Eberle almost 13 yearsAsk your teacher, that kind of stuff is pretty subjective.
-
mrivard almost 13 yearsI have found this article helpful to understand what's harmful about goto. The comparison with
break
is probably well meaning, but actually misunderstood. Perhaps you can educate your professor on this ;) In my experience professors don't know much about the craft of programming. -
Voo almost 13 yearsThe only really, undisputable bad thing about this is in my mind, the fact that
do {} while (true)
is equivalent towhile(true) {}
and the latter is by far the more conventional form and much clearer. -
Steven almost 13 yearsIf anyone doesn't appreciate the simple expressive power of
break
, they should try programming in a language without it. It doesn't take too many loops before you'll wish for it! -
aaaa bbbb almost 13 yearsI disagree with the homework tag.
-
Brett almost 13 years
do {} while (true);
nicely matchesdo {} while (false);
. :^) -
jprete almost 13 yearsBreaks are not bad, and are often good. Labeled breaks are not bad when used carefully, judiciously, and obviously. Neither one is equivalent to goto, which is a completely arbitrary jump from anywhere to anywhere.
-
zzzzBov almost 13 years@jprete, to add to your comment: labeled breaks are wonderful for escaping nested loops. Nested loops should be avoided, and therefor, so should labeled breaks. However, if you need 'em, use 'em.
-
Halberdier almost 13 yearsIf the break escape were evil, it wouldn't have been implemented in modern languages that instead avoid goto. This said, "real programmers aren't afraid to use GOTOs" either :)
-
kokbira almost 13 yearswell "break" only substitutes some ifs and the use of a flag...
-
Marjan Venema almost 13 yearsAnd (in Delphi) you need Break to prematurely end a for-loop (as in Delphi you cannot change the value of the iterator index within the for loop body). Very useful. Wouldn't want to have to resort to while loops to iterate over an array or collection and "break" out as soon as you have found what you were looking for...
-
TheBlastOne almost 13 years@Marjan Venema -- good point. But sure enough this need experience. Programmers not familiar with this bad of tricks will better understand the while solution (that is, the one replacing the For, not the while true do..."break").
-
Marjan Venema almost 13 years@TheBlastOne: Breaking out of for loops (and while loops for that matter) is part of the "standard Delpni vocabulary". If you look at more than trivial Delphi example code, you will encounter this construct pretty soon/often.
-
TheBlastOne almost 13 years@Marjan Venema: Yeah, I did not disagree on that.
-
Jacqlyn over 10 yearsI was called up in front of the class because I did this on a test. The reason I was called out was because I did
do while(true)
, not because I usedwhile(true)
. My professor saiddo while true
was confusing to read, and since ado while true
is functionally the same as awhile true
there's no reason not to use the latter, which is easier to read straight off. I disagree with the people down there who say that using awhile true break
is the same as using a boolean in thewhile
. A break statement is fundamentally different, since it terminates at that spot. -
matbrgz almost 9 yearsThe academic reaction to the spaghetti code in languages without more powerful flow controls mechanisms than
GOTO
has been very strong and if you unconditionally accept the "GOTO is bad" statement it is very easy to extrapolate into that "any GOTO-like flow mechanism is bad". Sounds like it happened here. I've found that I rarely have the need forbreak
/continue
but frequently for refactoring out a method where they are then replaced byreturn
. -
wide_eyed_pupil almost 9 yearsre: What's wrong with
do-while (true)
? Apart fromwhile-do
being clearer, I think main reason some senior programers tell students don't usewhile-loops
usefor-loops
instead is because under certain unplanned for conditions awhile-loop
can become an infinite loop, i.e. potentially a race condition and it's much harder/more annoying to debug. I got told that by someone who's code I respect once but didn't dwell on it. So I always refactor tofor-loop
if I can. obviously not really possible if you want to break inside the loop unless language allowsbreak
infor-loops
. -
Martin Pfeffer about 7 years@Voo equivalent?
while(..){..}
!=do {..} while(..)
, since the do-while is guaranteed to run at least once! -
Voo about 7 years@MartinPfeffer I'll keep that in mind for the time when
true
starts evaluating to false. -
Kellen Stuart about 6 yearsYou should email this page to your professor :)
-
user207421 over 4 yearsYour teacher is misinformed, or indeed uninformed. This attitude is common in academia, but non-existent out here in the real world. It is simply not the case that festooning your code with additional booleans or other state variables is superior in any way to using
break
, and there are good formal arguments to be made against additional state. The argument from Dijkstra does not hold.
-
-
JHarnach almost 13 yearsI agree it's not the first tool I reach for, but it just seemed to take care of the problem so cleanly, and I do like clean code.
-
Jon Skeet almost 13 yearsBecause keeping a boolean flag is probably no clearer, and may well be less clear, in my experience?
-
Daniel Leschkowski almost 13 years@Jon Skeet Well its a question of going with a good habbit or training yourself a bad one by using break. A bool called "running" is not clear to you? Its obvious, easy to debug, and as i mentioned before a good habbit is a good thing to keep. Where is the problem?
-
Sled almost 13 yearsI like your suggestions since the terminating condition is much more visible. That means when reading the code you will sooner get a understanding of what it is trying to do. I would never use an infinite loop but use your two versions frequently.
-
Jon Skeet almost 13 yearsA bool called running that then requires me to have an
if (running)
within the loop, indenting all the rest of the code when all I want is to exit the loop is definitely less clear to me than a simple break statement which states exactly what I want do. You seem to be considering using break as a bad habit axiomatically - I don't think of it as such. -
JHarnach almost 13 yearsThe consensus is that a flag is better than break largely because it expresses intent? I can see that to be beneficial. All solid answers, but I'll mark this as accepted.
-
Daniel Leschkowski almost 13 yearsWhy would you have an if (running) within the loop? As with break at the end of loop you check if you want to break out and flip the flag instead of using break and use the flag in while(running) instead of while(true). I dont get your point, seriously. I would agree that a pragmatic coder might use break in certain situations, but i really dont get the comments you made under my suggestion
-
Jon Skeet almost 13 yearsYou're assuming you don't need to do anything within the loop after you've determined whether or not to quit. For example, in the OP's situation he needs to ask for more input if he's not quitting.
-
Jon Skeet almost 13 yearsBoth of these still suffer from the rest of the loop being polluted (in some situations at least) by having to keep going to the end of the body of the loop even if you know you're breaking. I'll put an example in my answer...
-
Daniel Leschkowski almost 13 yearsAs in the post of the op the ask for more is the loop as i understood. And in that particular situation a break is no more clear then a flag
-
Jon Skeet almost 13 yearsI've added an example to my answer to show exactly what I mean. And no, I'm not going to chat because I'm going doing various other things. Flitting from place to place doesn't work well with chat.
-
Jon Skeet almost 13 yearsThe "ask for more" is the final comment of the block - in other words, code to be executed only if we haven't broken out of the loop.
-
Clockwork-Muse almost 13 yearsAre things like this reasons to extract some of the code from (or around) the loop and place it in external methods, allowing for (literal) early returns?
-
Jon Skeet almost 13 years@X-Zero: Yes, sometimes. If you can turn the "break" into a "return" that's often goodness... although you might still end up with a
while (true)
-
JHarnach almost 13 yearsI actually like the example you posted more. I'm in different on the while vs do while part, but here your use of break looks fine and still clear to the reader what's happening. +1
-
Daniel Leschkowski almost 13 yearsThough i wont use it, and though i wont use the break statement as i - personal opionion - think its not more complicated to read (as far as i concern, the code "speaks" clearly to me in both ways - with or without break), ill give you an upvote because i can see you have a point. Which - in my humble oppinion - i dont have to share, but understand that for some it might be the right solution. I for myself believe that good habbits should be trained and kept if there is no drawback. And i dont see any, but as you teach using break, you might lead beginners to misusage of break.
-
trutheality almost 13 yearsIt is actually not that hard to "clean up the clutter" in the non-break version: just do
if( !(stop = condition ) ){ dostuff; }
, in fact, if the condition is complicated enough, puttingstop = condition;
(orrunning = condition;
) on a line by itself, and reusing the value thereafter might actually improve readability. -
Jon Skeet almost 13 years@trutheality: I prefer most of my code to be as unindented as possible though. And a condition with a compound assignment feels more complicated to me.
-
El Marcel almost 13 yearsYou could just put an if at the end like in your example. I actually used to be allergic to this kind of construct because I always associated loops with iterators and incrementing values, but now I see the value of the declaration of the loop var and the check being right next to the FOR. It's tidy, it's outside the braces. It's not always the best solution, but useful in some cases.
-
aaaa bbbb almost 13 yearsI like Jon Skeet's answer better. Also, while (true) {} is MUCH better than do {} while(true)
-
El Marcel almost 13 yearshaha, "true" :) they work identically anyway.
-
Wedge almost 13 yearsOr just use a function: while(getSomeInput()), instead of break use return.
-
Kibbee almost 13 yearsI hate that Dijkstra ever wrote that GoTo article. While GoTo certainly can was often was abused in the past doesn't mean you shouldn't ever use it. Also, Exit For, Break, Exit While, Try/Catch are all just specialized forms of Goto. Gotos can often make code more readable. And yes I'm aware that anything can be done without Goto. That doesn't mean it should.
-
Lie Ryan almost 13 years@Kibbee: the list of specialized forms of goto goes further: if, for-loop without break, while-loop without break, break, continue, function calls, exceptions, .... If you remove all forms of hidden goto, I think you'd be left with a language that isn't Turing complete.
-
Ken Bloom almost 13 yearsIn fact, if you're using a
while (true)
loop instead of one of these conventional input loops, you might be forgetting to check for the end of the file. -
poolie almost 13 yearsYou're accomplishing this effectively by stuffing the first part of the loop into the
while
conditional. In the final Java condition it's already getting fairly hefty, and if you had to do extensive manipulation to decide whether to continue or not, it may get quite long. You could split it out into a separate function, and that might be best. But if you do want it in one function, and there's nontrivial work to do before deciding whether to continue,while(true)
may be best. -
poolie almost 13 yearsIf the loop starts off with
while (true)
it's pretty obvious that there's going to be abreak
orreturn
inside it, or that it will run for ever. Being straightforward is important, butwhile(true)
isn't especially bad, by itself. Variables that have complex invariants across loop iterations would be an example of something that causes much more angst. -
poolie almost 13 yearsA
break
statement means just that: exit the loop, nothing else. A boolean can be manipulated, checked, and set in multiple places, and people have to trace their interaction to see whether and when the loop does actually terminate. All else being equal,break
is simpler. -
Daniel Leschkowski almost 13 yearsWhat you seem to overlook are certain things like nested loops where break makes following the code more complicated, rather then making it easier as you seem to think break always does. And if you screw up your code by obfuscated usage of a flag, thats way another problem...
-
Donal Fellows almost 13 years+1: There are additional complexities with
for
loops whencontinue
statements are involved, but they're not a major extension. -
Donal Fellows almost 13 yearsI always try to make assignments be on their own line, and I do this across many languages. It makes the code clearer (changing the state of the system is an important thing) and it also helps a lot if I have to attach a debugger or other such tool (a trick I learned from John Ousterhout).
-
Jon Skeet almost 13 years@Donal: I usually avoid compound assignments other than for the very common
while ((line = reader.ReadLine()) != null)
pattern. -
Donal Fellows almost 13 yearsI don't even like that one particularly, TBH. Not that it comes up that often, thankfully.
-
Jon Skeet almost 13 years@Donal: I personally like encapsulating that pattern in an iterator, but where it's tricky to do that, it's a familiar enough pattern that I don't mind it.
-
Ken Bloom almost 13 years@poolie: Then it's probably best to use the read command as the loop condition (which checks for EOF), and check for your other conditions inside the loop as break statements.
-
Kibbee almost 13 years@Lie Ryan: Exactly, you can put lipstick on a pig, but it's still a pig. I've seen enough code (good and bad) in my day to know that Goto is neither sufficient or necessary for bad code. Even in old Basic, there were no function calls just GOSUB, which was very basic advance over GoTo, and that ON ERROR GoTo was the only error handling mechanism in VB all the way until it turned into VB.Net
-
dascandy almost 13 yearsI usually use a for loop when there's a sequence I want to run across, and a while loop when there's a condition that I want to meet. This keeps the code more legible imo.
-
dascandy almost 13 yearsTry going three levels deep in a search and then somehow breaking out. The code is going to be much worse if you don't just return from that point.
-
kokbira almost 13 yearsif you work in a low memory "environment", it's better to avoid creating variables and condition checks...
-
oosterwal almost 13 yearsGOTOs are bad? The Assembly/Machine Language code that our programs turn into is riddled with the equivalent of GOTO.
-
dr jimbob almost 13 yearsI think setting
exit_time = false; while(!exit_time) { execute_stuff(); }
anddo { execute_stuff(); } while(! exit_time );
are both much clearer than having anif( condition ) { break; }
at the end of a loop with awhile(true)
. Breaks are short-circuits to loops -- perfectly fine when used as a short-circuit in the middle of a loop, but you should just evaluate a condition in the while statement vs having a break at the end of a loop. -
JHarnach almost 13 years+1 for the comment about defensive programming.
-
Billy ONeal almost 13 yearsYour second example can be shortened to
for (;;)
-- which is in fact the usual way to do this in some languages (e.g. C++) -
Dave almost 13 yearsFor what it's worth,
gets()
isn't common convention. It's highly conducive to buffer overflows.fgets(buffer, BUFFER_SIZE, file)
is much more like standard practice. -
Ken Bloom almost 13 years@Dave: I've now edited the answer to use
fgets
. -
El Marcel almost 13 yearsYeah, sure but you've still got to put that code somewhere. I was trying to show that the for struct can be (ab)used for more than iterators and fixed number counting.
-
Razor almost 13 yearsI disagree with this. A condition can tell you what's going on upfront without having to read the code (useful if you are skimming). Wouldn't while(price < priceDiscountThreshhold) tell you more than while(true) ?
-
Jon Skeet almost 13 years@Vince: Yes, and that's great if you can express the condition easily at the start of the loop. But sometimes you can't - and that's the situation we're talking about. Please note the first couple of sentences of my answer.
-
Pacerier almost 13 years@Connell wait till your teacher hear's that!
-
Connell almost 13 yearsI'm self taught on the programming front. All I have to judge by is my IT teacher in secondary school, who taught us to make websites using Dreamweaver in such a way that EVERYTHING was an absolutely positioned div...
-
Pacerier almost 13 years@Connell up my post to show your agreement
-
Jon Skeet almost 13 years@Ismail: I hope not. Posts should be judged solely on their content, not on the author. Heck, I'd even downvote an Eric Lippert post if I felt it was inaccurate/unhelpful. That hasn't happened yet though :)
-
filip-fku almost 13 years"Those who can't do, teach." - That's a pretty big generalization don't you think? Should doctors, engineers, pilots, etc all be self taught since their instructors are incompetent according to you?
-
Pacerier almost 13 years@filip-fku wow wow~ cool it cool it!
-
filip-fku almost 13 yearsSorry that came out more serious sounding that I intended! I just thought that sweeping generalization was not fair. Sure there are crappy teachers but there are also very good ones - like with any career path.
-
TheBlastOne almost 13 yearsThe more code from other people one has had to read in his life, the more one will +1 this answer. (And the other way around.)
-
Connell almost 13 yearsI didn't make the generalisation myself, it's a fairly common phrase, especially at my old college. Sorry if I offended anyone. See blogcritics.org/culture/article/those-who-cant-do-teach.
-
Kerrek SB over 12 yearsI think in C you really want to store the result of the read to see how much data you actually have... And please don't encourage
abusing namespace std;
in C++ :-) -
Ken Bloom over 12 years@KerrekSB
fgets
doesn't work that way. From the manpage: "gets()
andfgets()
returns
[the buffer that you passed in] on success, and NULL on error or when end of file occurs while no characters have been read." -
Kerrek SB over 12 years@KenBloom: Oh, sorry, confused it with
fread
... errr, so how do you know if you got a whole line? I guess you have to check where the NULL is? -
Ken Bloom over 12 years@KerrekSB: you call
getline
, which dynamically allocates its own memory. I'll update my answer. -
Theraot over 10 yearsIn regard to that comic: while do-while can't do all that while can do, do-while sometimes is better doing what do-while can do even that while can also do.
-
Florian F over 9 yearsIn your example, the code is stupid not because of the choice of the while(true) but because of the idea of putting a loop around the code.
-
juzzlin over 9 yearsIndeed, what was the point of that loop? :)
-
Dawood ibn Kareem over 9 yearsDoesn't anyone write
for (;;) {
any more? (Pronounced "forever"). This used to be very popular. -
LegendLength over 8 yearsWell said. It's like using a doing a for loop with: while(true) {i++;...}. You are burying the loop condition inside the loop rather than in the 'signature'.
-
LegendLength over 8 yearsAnother reason for good habits is consistency. If you use a different style for small loops vs big loops it's just yet another thing to think about.
-
caylee over 6 yearsShorter would be
guard = condition
:-) -
Roy Prins about 6 yearsHere is Edsger Dijkstra's paper. It's a good read.