The rap against "while True:" loops

G

greg

RDrewD said:
my_prissy_little_indicator_variable = true
while (my_prissy_little_indicator_variable){
<body>
}
isn't satisfying because it doesn't guard the <body> with any
assurance that the loop invariant will be true before you enter into
that block of code.

The loop invariant and the exit condition are different things.

The loop invariant is supposed to be true every time the loop
invariant is tested, including on the last iteration, so that
when the loop exits, you can assert that the loop invariant
*and* the exit condition are both true. The trick is to choose
them so that together they ensure whatever it is the loop is
meant to accomplish.

If the exit test is half way through the loop, then the loop
invariant doesn't have to be true before the loop is entered --
it only has to be true by the time the exit test is encountered
for the first time. In other words, the first execution of the
part of the loop before the exit test is really part of the
initialization, and has to be treated as such in the analysis.
I don't mind while(true) for the case of "do forever" like those
launcher requirements Peter Billam wrote about up above in this
thread. It essentially says the loop invariant is that the system
hasn't crashed yet.

I think it's more accurate to say that, because there is no exit
test, there is no point in the loop at which a loop invariant
has to be true, so there is no need for a loop invariant, at least
in the sense the term is used in the formal theory of correctness
proofs for loops.

It may be desirable to impose invariants on the state of the
system at various points in the loop for other reasons, although
those might better be described as parts of the contracts between
the loop and the functions it calls.

(BTW, "the system hasn't crashed yet" can't be the loop invariant,
because if the loop ever exits then it means the system must have
crashed, so the loop invariant is no longer true!)
 
G

greg

Mensanator said:
while not done:
...
if n==1: done = True
...

Seems to me that 'while not done:' is no better than
'while True:', because in both cases you have to look
inside the loop to find out what the exit condition
is.

Using a more meaningful name for the flag can help,
but you can't teach someone that just by giving them
an overly simplified rules such as "never use
while True:". They'll probably just replace it with
'while not done:' and think they've improved things,
without ever really understanding the issue.
 
G

greg

kj said:
I'm coaching a group of biologists on basic Python scripting. One
of my charges mentioned that he had come across the advice never
to use loops beginning with "while True".

It's possible this is something he was told in relation to
another language that has more options.

For example, in C there's for(;;) as an alternative, although
there's not much to choose between them. Also you can often
use an assignment-as-condition trick to squeeze a loop-and-
a-half into a while(), and you have do-while loops for
testing at the end.

Python is much more limited -- anything which isn't a
for has to be a while of some shape, so it's harder to
avoid while True without introducing extra complexities
into the code.
 
L

Luis Zarrabeitia

In this situation, the middle exit works best -- using
non-optimal Python

        while True:
                lin = file_object.readline()
                if not lin: break
                do something with lin

Actually, in python, this works even better:

for lin in iter(file_object.readline, ""):
... do something with lin
 
G

Grant Edwards

I think you meant the other way; the above is the simplest loop case, with
the test at the start.

Except the test at the start is meaningless when it comes to
reading the code and troubleshooting. What counts are
assignments to my_prissy_little_indicator_variable inside the
loop. And those aren't really any easier to spot that "break"
statements.
 
M

Mel

Luis said:
Actually, in python, this works even better:

for lin in iter(file_object.readline, ""):
... do something with lin

And one can do this oneself. Faced with

while True:
stuff_required_to_make_the_decision()
if the_decision():
break
other_stuff()


Wrapping the `stuff_required_...` and `the_decision` up into a generator
would simplify the statement, and if it were done well the code overall
would probably be better.

Mel.
 
L

Luis Zarrabeitia

What about ....

Gah.

You are right, of course!

Even my for should've been:

for lin in file_object:
...

and nothing more.

I use that iter "trick" only when I don't want the buffering (like, when I'm
reading from stdin in a squid authenticator helper).

I guess that the 'for line in f' is so... natural for me, that the only reason
I could think for writing "while True" for a file iteration was when I needed
to use readline explicitly.

But yes, "with"!
 
M

Mensanator

Seems to me that 'while not done:' is no better than
'while True:', because in both cases you have to look
inside the loop to find out what the exit condition
is.

Using a more meaningful name for the flag can help,
but you can't teach someone that just by giving them
an overly simplified rules such as "never use
while True:". They'll probably just replace it with
'while not done:' and think they've improved things,
without ever really understanding the issue.

You're missing the point. It's not that you have to
look inside for the terminating condition. It's that
you don't need a break.
 
J

John Reid

Mensanator said:
You're missing the point. It's not that you have to
look inside for the terminating condition. It's that
you don't need a break.

Nothing wrong with a having a break IMHO.

while not done:

seems very dangerous to me as you'd have to

del done

before writing the same construct again. That's the sort of thing that
leads to errors.
 
E

Ethan Furman

Mensanator said:
You're missing the point. It's not that you have to
look inside for the terminating condition. It's that
you don't need a break.

What's wrong with breaks?

I'll agree that they can be overused and abused, but I am not aware of
*any* programming costruct that cannot be. If you rule out one way of
doing things for every situation you can end up making messes just as
bad as the ones you're trying to avoid.

Good programming, as all good endeavors, requires thinking too.

~Ethan~
 
M

Mensanator

Nothing wrong with a having a break IMHO.

My opinion is that there is everything wrong with
having a break. I don't think I have ever used one,
I write code that doesn't depend on that crutch.
while not done:

seems very dangerous to me as you'd have to

del done

before writing the same construct again. That's the sort of thing that
leads to errors.

Duh. I won't write silly code like that either.
If I need more than one loop structure then I'll
do something like

while not done_with_this


while not done_with_that

Besides, since I _always_ initialize the flag
before entering a loop, the flag can be reused
and doesn't have to be deleted (as long as the
loops aren't nested). And since I don't use goto,
there's no chance the initialization can be avoided.

The best way to avoid the pitfalls of spaghetti
code is to not write it in the first place.
 
F

Falcolas

My opinion is that there is everything wrong with
having a break. I don't think I have ever used one,
I write code that doesn't depend on that crutch.







Duh. I won't write silly code like that either.
If I need more than one loop structure then I'll
do something like

    while not done_with_this

    while not done_with_that

Besides, since I _always_ initialize the flag
before entering a loop, the flag can be reused
and doesn't have to be deleted (as long as the
loops aren't nested). And since I don't use goto,
there's no chance the initialization can be avoided.

The best way to avoid the pitfalls of spaghetti
code is to not write it in the first place.

How do you manage code where you need to drop out of a neatly written
for or while loop early? I don't use break frequently, but just like
gotos, it does have it's place in well written code.

Glad to hear, by the way, that you don't use gotos in Python. =D

Garrick
 
M

Mensanator

How do you manage code where you need to drop out of a neatly written
for or while loop early?

I don't. If I thought there would ever be a case when
a for loop had to exit early, I wouldn't use a for loop.

Similarly, if I ever felt the need to escape from a
while loop, I would rewrite it to avoid that situation.
I don't use break frequently, but just like
gotos, it does have it's place in well written code.

Glad to hear, by the way, that you don't use gotos in Python. =D

Python doesn't have goto? Gee, I guess I never looked for
one. Learned my lesson from Pascal, eh?
 
R

Raymond Hettinger

[kj]
I use "while True"-loops often, and intend to continue doing this
"while True", but I'm curious to know: how widespread is the
injunction against such loops?  Has it reached the status of "best
practice"?

This is the first I've ever heard of such an quasi-injunction.
Like you, I use "while True" often. We use it frequently
in the standard library and have no PEP 8 admonition
against it, nor does pychecker report it as a negative practice.
The use of "while 1" loops has a long history in other langauges
as well.

So, if you hear someone make-up a new "best practice" proscibing
"while True", just smile and continue to write programs as you
have been. You will not be alone. Many excellent programmers
write "while True" whenever it is called for.


Raymond
 
P

Paul Rubin

kj said:
I use "while True"-loops often, and intend to continue doing this
"while True", but I'm curious to know: how widespread is the
injunction against such loops? Has it reached the status of "best
practice"?

E. W. Dijkstra used to advocate that every loop have exactly one entry
point and exactly one exit point, i.e. no multiple break statements.
This is probably a misstatement, but I believe that the purpose was to
be able to specify a precondition at the loop entrance and a
postcondition at the exit, and be able to verify the conditions more
straightforwardly than if there were multiple exit points. But, that
doesn't specifically seem to speak against "while True:". For
example, Ada has a loop construct where the test and break is in the
middle of the loop.
 
S

Steven D'Aprano

My opinion is that there is everything wrong with having a break. I
don't think I have ever used one, I write code that doesn't depend on
that crutch.


Using break can avoid a lot of complication in loops. There's no need to
force every loop to have a single exit point (or for that matter, for
every function to have a single return). Compare the straightforward
implementation of a simple linear search:

for item in seq:
if cond(item):
print item
break

versus doing it without a break:

found = False
for item in seq:
if not found and cond(item):
print item

or:

found = False
seq = iter(seq)
while not found:
item = seq.next()
found = cond(item)
if found:
print item

The first is obviously correct, and efficient (it stops searching when it
has found a result). The second and third avoid using a break, but at the
cost of complicated, inefficient code which isn't obviously correct. If
you need to post-process item before returning, it's simple to replace
the return with a break.

The best way to avoid the pitfalls of spaghetti code is to not write it
in the first place.


break does not necessarily lead to spaghetti code. Avoiding break just
because it is a "goto" is cargo-cult programming -- following the magic
incantations with no understanding of the *reasons* for when gotos should
be used and avoided.

The danger with goto is that it is an *unstructured* jump. break,
continue, return, yield, for, while are all *structured* jumps. They can
be abused, like anything, but they're not inherently dangerous.
 
J

John Reid

Mensanator said:
My opinion is that there is everything wrong with
having a break. I don't think I have ever used one,
I write code that doesn't depend on that crutch.
I guess its crutch-iness is in the eye of the beholder. You seem to have
a dogmatic view about this.
Duh. I won't write silly code like that either.
If I need more than one loop structure then I'll
do something like

while not done_with_this


while not done_with_that
This is neither clean or well scoped.
Besides, since I _always_ initialize the flag
before entering a loop, the flag can be reused
and doesn't have to be deleted (as long as the
loops aren't nested). And since I don't use goto,
there's no chance the initialization can be avoided.
Initialising the flag is just another line of code that has to be
interpreted later. I didn't notice the initialisation in your original post.
The best way to avoid the pitfalls of spaghetti
code is to not write it in the first place.
I agree. With 'break' it is obvious what the code does and there are
fewer lines to write in the first place and comprehend in the second.
 
M

Mensanator

I guess its crutch-iness is in the eye of the beholder. You seem to have
a dogmatic view about this.

No, it's just that the OP was asking whether
avoiding "while True" is considered Best Practice.
How can you answer such a question without sounding
dogmatic?
This is neither clean or well scoped.




Initialising the flag is just another line of code that has to be
interpreted later. I didn't notice the initialisation in your original post.

"Just another line that has to be interpreted later"
is a strange comment in the context of "del done".
I agree. With 'break' it is obvious what the code does and there are
fewer lines to write in the first place and comprehend in the second.

Do you consider Perl golf to be Best Practice?
 
J

John Reid

Mensanator said:
No, it's just that the OP was asking whether
avoiding "while True" is considered Best Practice.
How can you answer such a question without sounding
dogmatic?
I was just pointing out your style of programming seems inflexible.
"Just another line that has to be interpreted later"
is a strange comment in the context of "del done".
Interpreted in the sense that the maintainer of the code interprets it,
not the machine.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,060
Latest member
BuyKetozenseACV

Latest Threads

Top