A common "error" (not too serious) that I see in
beginning Python (and no doubt other languages,
but Python is the one I'm teaching), is having a
while condition that appears to put a lid on things,
but then the flow all leaks away through break
statements, such that the "front door" condition
is never revisited.
while guess != secret:
guess = int(input("Guess?: ")
if guess == secret:
print("You guessed it!")
break
else:
print("Nope, try again...")
What's messed up about the above code is you
never really go back to the top in the case
where you'd get to leave. Rather, you exit by
the back door, through break.
So in that case, wouldn't have been simpler and
more elegant, even more "correct" (dare I say it)
to have gone:
while True: # no ifs ands or buts
guess = int(input("Guess?: ")
if guess == secret:
print("You guessed it!")
break
else:
print("Nope, try again...")
I see lots of heads nodding, and that could be
the end of the matter, but then a next question
arises: wouldn't this also be a more correct
solution?:
while guess != secret:
guess = int(input("Guess?: ")
if guess == secret:
print("You guessed it!")
continue # instead of break
else:
print("Nope, try again...")
We're back to having a variable while condition,
not a boolean constant, but this time we actually
exit by means of it, thanks to continue or...
while guess != secret:
guess = int(input("Guess?: ")
if guess == secret:
print("You guessed it!")
else:
print("Nope, try again...")
... thanks to no continue. This last one is getting
a thumbs up, but then I'd pause here and say
"continue" can be easier on the eyes. It's
unambiguous where it takes you, in contrast
to having to scan on down the gauntlet, looking
for possibly other open doors. "What happens
next" should not require scanning ahead too
far. Help us not to get lost. Be a civic-minded
coder.
I'm thinking of a programming style that advises
two things:
(a) if you use a while condition that's variable,
that's expected to change, then your goal should
be to always exit because of that, i.e. that should
be your only exit point. Even if some other
criterion suggests exiting, you have the option
to flip that "lid" at the top, to crack that front
door, and bounce the ball out.
(b) which is why 'continue' is your friend. You
are showing the user where your 'break' statements
are, except you don't use "break" statements, as
you've given a non-constant condition, and your
aim is to make that your ONLY exit point.
In short: never use break to exit a while loop
unless your condition is while True.
Instead, always flip the condition and exit
through the font door.
However, as soon as I make that rule I can
think of good reasons to break it. The other
programmers in the room are shaking their
heads. Won't we lose information, needed
elsewhere in the program, if we "artificially"
force a True condition to False. Aren't we, in
effect, lying? That concern could be addressed.
Keep all the info true, just treat the "lid
condition" (it "keeps a lid on it") as a flag.
Go ahead and remember the user's guess.
allowed = 5
tries = 1
exit = False
while not exit: # no other way out
guess = int(input("Guess?: ")
if guess == secret:
print("You guessed it!")
exit = True # instead of break
continue
print("Nope, try again...")
tries += 1
if tries == allowed:
print("You've maxed out")
exit = True
continue
I think we all understand the main issue:
writing reader-friendly code, and rules for doing
so. There's something comforting about approaching
a while loop and knowing its not a leaky sieve,
riddled with back doors, maybe even an exit( )
time bomb. But in the recursion world we want
a minimum of two exits usually: when another
round is called for versus when we've "hit bottom".
Can we have it both ways?
Conclusions:
Lets not be too hasty with rules of thumb
and:
Lets keep the reader in mind when writing code.
Just because the interpreter knows to compute
the flow unambiguously, doesn't mean all ways
of writing it are equally reader-friendly.
What may seem a gratuitous gesture, an
unnecessary flourish, may actually promote
reader comprehension of your code, and that
should be a goal as much as satisfying the
interpreter.
Kirby