[Python-ideas] for/else statements considered harmful

Nick Coghlan ncoghlan at gmail.com
Thu Jun 7 02:53:22 CEST 2012


On Thu, Jun 7, 2012 at 9:58 AM, Bruce Leban <bruce at leapyear.org> wrote:
> If we could go back in time I would completely agree. But since we can't,
> flipping meaning of else would be too error inducing and therefore not at
> all likely.

The meaning of the "else:" clause on for and while loops is actually
much closer to the sense in "try/except/else" sense than it is to the
sense in "if/else".
Consider the following:
 for x in range(20):
 if x > 10:
 break
 else:
 # Reached the end of the loop
As an approximate short hand for:
 class BreakLoop(Exception): pass
 try:
 for x in range(20):
 if x > 10:
 raise BreakLoop
 except BreakLoop:
 pass
 else:
 # Reached the end of the loop
It's not implemented anything like that (and the analogy doesn't hold
in many other respects), but in terms of the semantics of the
respective else clauses it's an exact match.
Part of the problem is that the "else:" clause on while loops is often
explained as follows (and I've certainly been guilty of this), which I
now think exacerbates the confusion rather than reducing it:
The following code:
 x = 0
 while x < 10:
 x += 1
 if x == y:
 break
 else:
 # Made it to 10
Can be seen as equivalent to:
 x = 0
 while 1:
 if x < 10:
 pass
 else:
 # Made it to 10
 x += 1
 if x == y:
 break
This actually ends up reinforcing the erroneous connection to if
statements, when we really need to be encouraging people to think of
this clause in terms of try statements, with "break" playing the role
of an exception being raised.
So I think what we actually have is a documentation problem where we
need to be actively encouraging the "while/else", "for/else" ->
"try/except/else" link and discouraging any attempts to think of this
construct in terms of if statements (as that is a clear recipe for
confusion).
If anything were to change at the language level, my preference would
be to further reinforce the try/except/else connection by allowing an
"except break" clause:
 for x in range(20):
 if x > 10:
 break
 except break:
 # Bailed out early
 else:
 # Reached the end of the loop
To critique the *specific* proposal presented at the start of the
thread, there are three main problems with it:
1. It doesn't match the expected semantics of a "finally:" clause. In
try/finally the finally clause executes regardless of how the suite
execution is terminated (whether via an exception, reaching the end of
the suite, or leaving the suite early via a return, break or continue
control flow statement). That is explicitly not the case here (as a
loop's else clause only executes in the case of normal loop
termination - which precisely matches the semantics of the else clause
in try/except/else)
2. As Bruce pointed out, the meaning of the else: clause on loops
can't be changed as it would break backwards compatibility with
existing code
3. The post doesn't explain how the proposed change in semantics also
makes sense for while loops
Cheers,
Nick.
-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-ideas mailing list

AltStyle によって変換されたページ (->オリジナル) /