[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