[Python-ideas] Control Flow - Never Executed Loop Body

Steven D'Aprano steve at pearwood.info
Sun Mar 20 21:32:37 EDT 2016


On Sun, Mar 20, 2016 at 01:16:50PM -0700, Andrew Barnert via Python-ideas wrote:
> On Mar 20, 2016, at 11:12, Sven R. Kunze <srkunze at mail.de> wrote:
> > 
> > Issues
> > People I talked to suggested "else" as an alternative to "empty" because "empty is not quite clear". Unfortunately, "else" is already taken and is itself not quite clear. "then" has been proposed as an alternative for "else" in an attempt for proper understanding of "else". If that would be an accepted proposal, it would make room for "else" to be used for the usage of the "empty keyword proposed here.
> 
> Besides the backward compatibility issue, changing "else" to "then" 
> would be horribly confusing. I suspect anyone who thinks that would be 
> an improvement doesn't actually understand or like for...else, and 
> they'd be happier just eliminating it, not renaming it.

"then" is my idea, and not only do I understand "for...else", but I like 
it and use it, and certainly don't want to eliminate it. I just hate the 
keyword used.

Let me just start by saying that I realise that actually changing 
"for...else" to "for...then" is at least 8 years too late, so I know 
this is a non-starter. It would be particularly confusing to change 
"else" to "then" AND add a new "else" with different semantics at the 
same time.


> An else clause is testing that no break was hit inside the loop. Look 
> at a typical example:

That's one way of thinking about it. But I don't think it is helpful to 
think of it as setting an invisible flag "a break was hit inside the 
loop", and then testing it. I think that a more natural way to think 
about it is that "break" jumps out of the entire for...else compound 
statement. This has the big advantage that it actually matches what the 
byte code does in all the versions I've looked at.

The "else" block is *unconditionally* executed after the "for" block. 
There's no "if not flag". Hence "then" is a better name for the 
construct: "for ... then ...".

"break" doesn't set a flag, it jumps right out of the "for...else" 
statement altogether, not just out of the loop part, but the "else" 
part as well. (As I said, this matches what the byte code actually 
does.)

As a beginner, I spent a very long time completely perplexed and 
confused by the behaviour of "for...else" because I understood it to 
mean "run the for block, *or else* run the else block". In other words, 
I understood from the keyword that "else" ran *if the for block didn't*, 
i.e. when the loop iterator is empty. A perfectly natural mistake to 
make, and I'm not the only person to have made it.

This (wrong, incorrect) interpretation matches the most common and 
familiar use of "else", namely in if...else statements:

if ...:
    a
else:
    b


You can get a, or b, but not both. In English, "else" represents an 
alternative. This does not come even close to matching the behaviour of 
for...else, which (in the absense of a "break" executes a *and* b, 
rather than a *or* b:

for ...:
    a
else:
    b

I'm not Dutch, but I think that "else" is not a good name for a block of 
code which unconditionally executes after the for/while/try block.

I think it's also unfortunately that it often looks like an indentation 
error:

for x in seq:
    do_stuff()
    if condition:
        break
else:
    do_more()


I've seen people "fix" the indentation on code like this and wonder why 
the code then does the wrong thing.

But, like I said, we're stuck with it, and I'm not seriously proposing a 
change. I think we'd be better off now if the keyword had been "then" 
from the beginning, but the pain of changing it *now* outweighs the 
benefit.



-- 
Steve


More information about the Python-ideas mailing list