New clause in FOR and WHILE instead of ELSE

ELSE-clause in FOR and WHILE has unclear syntax. I suggest new clause instead: if COND: ... [elif COND: ...] [else: ...] This IF-clause like must be immediately after FOR- or WHILE-cycle (only comment allowed between). It looks like a regular IF, but COND is special. COND may be "break", "pass" or "finally". "if break:" - if used break-operator to exit cycle. "if pass:" - cycle executed 0 times. "if finally:" - cycle executed 0 or more times ("pass-case" is included in "finally-case"). For compatibility only "else:" means "if finally:". It's compatible enhancement. No new keyword. There can be no combination "break", "pass" or "finally" after "if"/"elif:" in current version. ----------------- This idea was suggested as enhancement issue (https://bugs.python.org/issue41272). Eric V. Smith (eric.smith) advised me to put this on the python-ideas mailing list (https://bugs.python.org/issue41272#msg373486).

On 11/07/2020 06:22, Олег Комлев wrote:
Just to spell it out: If I understand you correctly, you are proposing that after a 'for'/'while' loop 'if break:' has its intuitive meaning: "if the loop was terminated with a 'break'". 'if finally:' means "if the loop completed (possibly with zero iterations) *without* a 'break'" (equivalent to 'else' at present). 'if pass:' means "if there were zero iterations of the loop (obviously, without a 'break')" (I assume that a partial iteration terminated by 'continue' would count as an iteration) plus 'elif' when you want to handle more than one of the above. So if COND1: ... elif COND2: ... would be legal, but if COND1: ... if COND2: ... would not. Something to consider: Would it be legal to mix these CONDs with other conditions in the 'elif' chain? E.g. if break: ... elif x > 0: ... elif finally: ... I would be the first to agree that the use of 'else' after 'for'/'while' is one of Python's more obscure features (I understand even veterans trip up over it). I like the general idea and I like 'if break:', but IMO the meanings of the other two are not obvious. I would suggest 'if not break:' rather than 'if finally:'. (And PEP 8 could recommend it rather than 'else:'. :-)) My gut feeling (backed by no evidence) is that dealing with the case of zero iterations is not needed frequently enough to cater for it. And I don't know if there is a good way to spell it (which might be another reason not to do it). Plus it's something which could be added later. Best wishes Rob Cliffe

On Sun, Jul 12, 2020, at 00:16, Rob Cliffe via Python-ideas wrote:
What if "instead of a special kind of if clause that can only be placed after a loop", we simply defined these three special expressions [usable in any if/elif statement] to reference special boolean flags that are set after exiting any loop?

On Tue, Jul 14, 2020, at 17:55, Rob Cliffe wrote:
Sorry if this was unclear, but my idea is that they would be per-frame like local variables. Perhaps they could even be implemented *as* local variables, with assign statements emitted during loops by the compiler if they are used anywhere in the function. If that violates 'local transparency', so does using the same scope for ordinary local variables [such as, say, the iteration variable of a for loop, which can also be used 100 lines of code later]. And of course PEP 8 would forbid using them anywhere other than directly after a loop, but allowing them to be used in any if clause prevents you from having two different kinds of compound statement, which can't be mixed together, that both begin with the word "if".

On 07/11/2020 09:16 PM, Rob Cliffe via Python-ideas wrote:
My gut feeling (backed by no evidence) is that dealing with the case of zero iterations is not needed frequently enough to cater for it.
My personal experience is that the case of no iterations is frequent enough, and a big enough pain to deal with, that if we're making changes we should include a way to deal with it. Currently: if empty_iterable: # do whatever else: for it in iterable: # do something or maybe: obj = object for obj in some_iterator: do_stuff() if obj is object: # iterator was empty do_different_stuff() Either way, for obj in iterator: do_stuff elif empty: do_other_stuff() would be much nicer. -- ~Ethan~

What about adding `except` to the compound loop statement? That way in cases where there needs to be clarity you can raise a specific exception rather than just `break`. Keeping the logic of why you "break" the loop inside the loop and would also allow multiple reasons for breaking from a for loop to remain clear. e.g.
On Tue, 14 Jul 2020 at 05:33, Ethan Furman <ethan@stoneleaf.us> wrote:
-- Notice: This email is confidential and may contain copyright material of members of the Ocado Group. Opinions and views expressed in this message may not necessarily reflect the opinions and views of the members of the Ocado Group. If you are not the intended recipient, please notify us immediately and delete all copies of this message. Please note that it is your responsibility to scan this message for viruses. References to the "Ocado Group" are to Ocado Group plc (registered in England and Wales with number 7098618) and its subsidiary undertakings (as that expression is defined in the Companies Act 2006) from time to time. The registered office of Ocado Group plc is Buildings One & Two, Trident Place, Mosquito Way, Hatfield, Hertfordshire, AL10 9UL.

On 14.07.20 09:54, Mathew Elman wrote:
That can be done already today by putting the `for` loop in the `try` body. Also here `else` should rather mean `did not raise` as for the normal `try/except/else` usage (and similar to how `for/else` means `did not break`). The more interesting part is to detect whether the loop did some work at all (i.e. whether the iterable was empty). But also this can be done with some small overhead: loop = Loop(iterable) for x in loop: pass if loop.empty: pass The `Loop` class here wraps the sentinel logic required to detect if the iterable was empty.

On Tue, 14 Jul 2020 at 12:38, Dominik Vilsmeier <dominik.vilsmeier@gmx.de> wrote:
It can, but my thought was that this would be sugar that made it easier to follow the logic
Yes sorry, I made an error. I confused myself about what else does, how ironic. This would be most useful for cases where break and not breaking were unclear.
The more interesting part is to detect whether the loop did some work at all (i.e. whether the iterable was empty).
This could be done by raising a "silent" exception that is handled by default (something like StopIteration), when trying to iterate an empty iterable. If the "NoIteration" exception is not caught explicitly it is ignored. Then you could have :
This may not be to everyone's taste, but to me it's better than the current state of things and clearer than having special if statements after a loop.
_______________________________________________
-- Notice: This email is confidential and may contain copyright material of members of the Ocado Group. Opinions and views expressed in this message may not necessarily reflect the opinions and views of the members of the Ocado Group. If you are not the intended recipient, please notify us immediately and delete all copies of this message. Please note that it is your responsibility to scan this message for viruses. References to the "Ocado Group" are to Ocado Group plc (registered in England and Wales with number 7098618) and its subsidiary undertakings (as that expression is defined in the Companies Act 2006) from time to time. The registered office of Ocado Group plc is Buildings One & Two, Trident Place, Mosquito Way, Hatfield, Hertfordshire, AL10 9UL.

Can I suggest that for loops the `else` would be a lot clearer if it was spelt `finally` as was done for PEP-0341 for try blocks and that we might possibly need one or more `on_…` clauses such as `on_break` and `on_finish` I think that this would be a lot clearer: for i in range(N): if i > 3: break; on_break: # Called if loop was broken print(i) on_finish: # Called if loop was not broken print("Loop Completed") finally: # Always called (replaces for…else) print("Loop Ended") Which I think would be a lot easier for newcomers to learn than try…for…else…except…else e.g.: try: for i in range(N): if i > 3: break; elif i % 2 == 0: raise ValueError("Odds Only"); else: # to if print(i) else: # Else to loop print("Loop Completed") except ValueError as err: print(err) else: # to try print("No Exception") finally: print("Try Ended") Where the multitude of elses makes my eyes cross. Steve Barnes

But in `for...else` the `else` call isn't always called, so changing `else` for `finally` doesn't make sense. What you're suggesting is replacing `else` with `on_finish` and adding `finally` and `on_break`. I agree that having `finally` could make the use cases of `else` clearer, but I am not convinced renaming "else" to "on_finish" would help the confusion for the 0 iteration case. I think that since this suggestion doesn't help with the 0 iteration case (my first idea here didn't either), it feels like added extra compound statements need to be immediately intuitive to be worth having - either because they read like a sentence or parallel existing python e.g. `try-except-else-finally` or `if-elif-else` etc. On Wed, 15 Jul 2020 at 06:47, Steve Barnes <GadgetSteve@live.co.uk> wrote:
-- Notice: This email is confidential and may contain copyright material of members of the Ocado Group. Opinions and views expressed in this message may not necessarily reflect the opinions and views of the members of the Ocado Group. If you are not the intended recipient, please notify us immediately and delete all copies of this message. Please note that it is your responsibility to scan this message for viruses. References to the "Ocado Group" are to Ocado Group plc (registered in England and Wales with number 7098618) and its subsidiary undertakings (as that expression is defined in the Companies Act 2006) from time to time. The registered office of Ocado Group plc is Buildings One & Two, Trident Place, Mosquito Way, Hatfield, Hertfordshire, AL10 9UL.

But `finally` with a `for` loop is redundant since the code can be placed just after the loop. For `try/except` it's a different situation since the exception might bubble up, so "normal" code after the `try` won't be reached. Also `on_break` doesn't seem really important since that code can be executed inside the loop right before the `break`. We already have `else` for `on_finish` and I think when recalling the analogy to exceptions it's not that confusing: a `try` block can be exited either normally (because all code has been executed) or because it raised an exception; here `else` means it exited normally. Similarly a `for` loop can terminate either normally by executing all iterations or because a `break` occurred; and similarly `else` means it terminated normally. On 15.07.20 08:47, Mathew Elman wrote:

The point is that `for-else` reads like "do this for loop ELSE (or but if you can't loop) do this", i.e. roughly equivalent to this:
or
But that isn't what it means. It means "do this for loop and if you deliberately break out, continue ELSE (or if you don't break out) do this". i.e. roughly equivalent to this:
or
pass
else:
print("you didn't break from the loop you maybe entered...")
which is not intuitive because `else` reads like it handles the unexpected case, which one would have guessed was either breaking out or not entering in the first place. On Wed, 15 Jul 2020 at 09:23, Dominik Vilsmeier <dominik.vilsmeier@gmx.de> wrote:
-- Notice: This email is confidential and may contain copyright material of members of the Ocado Group. Opinions and views expressed in this message may not necessarily reflect the opinions and views of the members of the Ocado Group. If you are not the intended recipient, please notify us immediately and delete all copies of this message. Please note that it is your responsibility to scan this message for viruses. References to the "Ocado Group" are to Ocado Group plc (registered in England and Wales with number 7098618) and its subsidiary undertakings (as that expression is defined in the Companies Act 2006) from time to time. The registered office of Ocado Group plc is Buildings One & Two, Trident Place, Mosquito Way, Hatfield, Hertfordshire, AL10 9UL.

I'm really glad that Олег Комлев has posted this suggestion to the list. Thank you! I found myself using this construction, and in December 2019 (that seems a long time ago) I discussed it face-to-face with Paul Piwek. He found this highly relevant article https://stackoverflow.com/questions/9979970/why-does-python-use-else-after-f... Here's a brief (and selective) summary of this SO page. The question was asked in 2012. The original poster wrote "No matter how I think about it, my brain can't progress seamlessly from the for statement to the else block." One of the answers references a talk by Raymond Hettinger, which "briefly addresses the history of for ... else". He attributes the concept to Don Knuth, and says that if Guido was thinking about the future he (GvR) would have called it no_break instead of else, so everyone would know what it did. I highly recommend that you watch RH's talk, 15:50 to 19:00 (min:sec). Transforming Code into Beautiful, Idiomatic Python https://www.youtube.com/watch?v=OSGv2VnC0go&feature=youtu.be&t=950 The Stackoverflow page also references a summary of earlier discussions that Steven D'Aprano kindly prepared and posted to this list (in 2009). https://mail.python.org/pipermail/python-ideas/2009-October/006155.html That's the end of my SO summary. In addition, there's Don Knuth's paper Structured Programming with goto statements (1974) Reprinted in https://www-cs-faculty.stanford.edu/~knuth/lp.html By the way, I happen to have a copy of this book (typeset by TeX, of course) and have more than once read the 1974 goto paper. (There we go. A loop with a break.) If you don't have ready access to a copy, you might like to look at http://people.cs.pitt.edu/~zhangyt/teaching/cs1621/goto.slides.pdf http://www.kohala.com/start/papers.others/knuth.dec74.html I think that's enough for now. And thank you again Олег, for posting your suggestion to the list. -- Jonathan

On 15/07/2020 09:20, Dominik Vilsmeier wrote:
+1
Also `on_break` doesn't seem really important since that code can be executed inside the loop right before the `break`.
Not true, because you might have multiple breaks. This would avoid putting the same code after each one. May I repeat: Spelling 'if break:' and 'if not break:' rather than say 'on_break:' etc. would avoid adding new keywords. I don't know what to do about the zero iterations case, though. Best wishes Rob Cliffe

On Mon, Jul 20, 2020 at 10:36 AM Rob Cliffe via Python-ideas < python-ideas@python.org> wrote:
It could be that if `break` appears somewhere that an expression is expected, it becomes an expression with the value 0 or 1 (or False or True) to indicate the number of breaks that happened in the previous loop, and similarly some other bit of code involving keywords can become the number of iterations of the previous loop. This could be represented by `for`, `len(for)`, `pass`, etc. So one might write: ``` for x in ...: ... if not pass: ... elif pass == 1: ... else: ... ```

This is a continuation of my previous post to this thread. Python's FOR ... ELSE ... , Raymond Hettinger has told us, has origins in some ideas of Don Knuth. For that reason, and others, I'll concisely review these ideas. In the very early days, a computer program was a sequence of commands. The goto <somewhere> command was used to create loops, and the IF command was used to break from loops. Often, this led to what was called spaghetti code. (In some versions of BASIC, the GOTO was to a line number.) In the 1960's ideas developed to remedy this situation. Edsger Dijkstra coined the phrase 'structured programming', and he was the author of the famous paper 'Go To Statement Considered Harmful'. (I recall reading that the title was supplied by Wirth.) Aside: This is in the context of source code. By 1970 there were higher level languages, which were compiled into machine code. Dijstraka I'm sure approved, within limits, of GOTO in machine code. One consequence of structured programming is to provide and guarantee such limits. Don Knuth's 1974 paper, Structured Programming with goto statements, finds merit in both sides of the question. One of his goals is "improved syntax for iterations and error exits, making it possible to write a larger class of programs clearly and efficiently without goto statements". Nearly done with the review. Knuth finds a result of Lipton, Eisenstadt and DeMillo especially noteworthy. Briefly, for every large n, there is an n-statement program using goto statements that cannot be 'nicely converted' to a structured program. By 'nicely converted' (my phrase) Knuth means that the structured program is either larger or slower or both than the goto program, with a numeric lower bound on by how much. (Size exponential in n, speed logarithmic in n, both with explicit constants.) This justifies Knuth's phrase "a larger class of programs" in the goal I just stated. Aside: Incidentally, Knuth's paper uses coroutines in his discussion of efficient implementation of Hoare's quicksort algorithm. In it he credits Strachey sharing with Knuth the importance of coroutines (or goto) for producing a conceptually simple solution to the problem of merging two binary trees. It might help if a tutorial on how to do this in Python, by using async and wait, was written. My next post will apply some of the concepts in Knuth's goto paper to FOR ... ELSE ... in Python. The above relies on a lot of implied knowledge. If you don't already have it, the above might be hard going. I hope it helps at least some of you. -- Jonathan

On Mon, Jul 20, 2020 at 03:22 Jonathan Fine <jfine2358@gmail.com> wrote:
That’s news to me (both that it’s due to Knuth and that Raymond said so). I invented it without awareness of prior art, by reasoning about the similarity between IF and WHILE (FOR followed from WHILE). —Guido -- --Guido (mobile)

On Mon, Jul 20, 2020 at 03:22 Jonathan Fine <jfine2358@gmail.com <mailto:jfine2358@gmail.com>> wrote: This is a continuation of my previous post to this thread. Python's FOR ... ELSE ... , Raymond Hettinger has told us, has origins in some ideas of Don Knuth. That’s news to me (both that it’s due to Knuth and that Raymond said so). I invented it without awareness of prior art, by reasoning about the similarity between IF and WHILE (FOR followed from WHILE). —Guido See Raymond's video "Transforming Code into Beautiful, Idiomatic Python" at https://www.youtube.com/watch?v=OSGv2VnC0go from 15 min 50 sec to 18 min 57 sec. On 20/07/2020 15:42, Guido van Rossum wrote:
Also, let me be clear that this feature will never be added to the language.
With respect, that seems pretty dogmatic, given that for...else is one of the most confusing features of Python. What would be so terrible about allowing, at minimum, `if not break:' as a synonym for 'else:'? Best wishes Rob Cliffe

On 21/07/2020 22:07, Barry wrote:
I'm sorry, of the above two points I don't understand 1. at all, and I only half understand 2. Please could you rephrase more clearly for an idiot like me.:-) But as to `if` after `for` being confusing, are you seriously saying that `else` after `for` is *less* confusing?

On Tue, Jul 21, 2020 at 10:07:47PM +0100, Barry wrote:
1. Because that not what else mean today. Its elif never looped.
py> for x in [1,2]: ... print("inside loop") ... else: ... print("elif never looped") ... inside loop inside loop elif never looped This is why I have long-argued that the keyword here should be *then* not else. The semantics are that the loop executes, *then* the following "else" block executes, unless we have transferred control elsewhere by jumping out of the loop with return, raise, or break. Mistaking the semantics for "if never looped" is a very common mistake. Welcome to the club :-) -- Steven

Hello, On Wed, 22 Jul 2020 09:45:31 +1000 Steven D'Aprano <steve@pearwood.info> wrote:
But no, loop executes, *or else* the following "else" block executes ;-). That's the logic of founding fathers. After one grasped that logic, one comes to appreciate a weird beauty of it. The verdict remains the same though: "Do Not Use".
[] -- Best regards, Paul mailto:pmiscml@gmail.com

On Wed, Jul 22, 2020 at 1:15 PM Paul Sokolovsky <pmiscml@gmail.com> wrote:
There's a buggy construct that I see VERY frequently in my students' code (which I'll show in Python syntax here, but this can happen in any language) that closely parallels the actual semantics of Python's for-else, and showcases its value. # Find the first two-digit number, or return 99 def find_big_number(pile): for number in pile: if number > 10: return number else: return 99 It's extremely common to see this "else" attached to its "if" in a way that prevents the loop from finishing. Now, obviously, in the case where you're using a "return" as the body of the else, you could just unindent it as unconditional post-loop code, but that doesn't work for other examples, and as a general rule, it seems that people like to think in terms of "if it is what we want, do this, otherwise do that". And that behaviour is exactly what a for-else loop does. ChrisA

On Wed, Jul 22, 2020 at 06:14:39AM +0300, Paul Sokolovsky wrote:
I am confused. I don't understand your comment. Your "But no" suggests to me that you are disagreeing with me. Your comment "loop executes *or else* ..." suggests that you are denying the evidence of the code, and defending the idea that either the loop runs, or the else clause runs, but not both. You literally say that the loop runs, *or else* (xor) the else block runs. But you say this in response to a demonstration that the loop runs, *and* the else block runs. So I am stuck in a "does not compute" moment. I cannot see any other interpretation of your comment apart from disagreement: "No Steven, you are mistaken, never mind that the code you copied and pasted demonstrates that the loop block and the else block *both* run, never mind that anyone can run their own tests to demonstrate that *both* run, that's wrong, either the loop runs *or else* the else block runs but not both." If there is another interpretion of your comment it is too subtle for me after a long and tiring day. I cannot see any interpretion other than you literally denying the reality of how for...else blocks work. And I cannot believe that you would do that. Surely I must be misinterpreting you. Hence, "Does Not Compute". What am I missing? -- Steven

Hello, On Wed, 22 Jul 2020 20:00:29 +1000 Steven D'Aprano <steve@pearwood.info> wrote: []
Nope, I'm not saying that. I'm saying that if loop can run, it runs. Else if it can't run (which happens when it's exhausted), then "else" runs. The only unclear thing here is that "break" skips it. That's not immediately obvious, but if you think about, it starts to make sense, because otherwise no "else:" would be needed at all. And I'm saying that not in justification of "else:", but as an example of learning how to understand what made the language author chose "else:" as the name of that clause. The above aren't my words either, that's what I read to grasp that stuff (and it stuck only when I peered thru enough bytecode). If there is any obvious conclusion to make from all that, that would be the same "Do Not Use" already mentioned. On the topic of "change something", I'd personally wouldn't find it a tragedy if: --- for ...: elif not break: --- was made a synonym of --- for ...: else: --- But I'm worried about the usual scope creep in the discussion here, with all the further "if break/if empty/if not empty" adhoc clauses. And I find "else: # if not break" to be pretty neat already, just need to crusade to make linters require it by default, as a second choice after unconditionally warn on using "else:" in the first place. Note that you'll need to make linter-crusade even if "elif not break:" is adopted, because "else:" stays put, for backward compatibility. -- Best regards, Paul mailto:pmiscml@gmail.com

Steven D'Aprano writes:
On Wed, Jul 22, 2020 at 06:14:39AM +0300, Paul Sokolovsky wrote:
But no, loop executes, *or else* the following "else" block executes ;-).
He means the loop *suite* executes (this includes "getting to" a break statement or other control flow that leaves the loop *statement* entirely), and if it doesn't, the else suite does. This is "why" such nonlocal exits differ from finally in that they don't run the else suite. I personally think this is a perfectly clear and convincing argument for "else" as the keyword for this statement (once "suite" is added to Paul's phrasing). This is why programmers should major in English, and do a graduate degree in programming if they really think they need a degree in programming.
You mean "the part of the loop *statement* that starts with 'for' or 'while'" runs, but this is somewhat inconsistent as the else suite is also part of the loop statement. I don't know of a concise but explicit way to express what you mean, although I understood it perfectly well.

On 23/07/2020 16:24, Stephen J. Turnbull wrote:
The upholders of the status quo regularly provide gallant explanations of why "else" is perfectly natural, even intuitive. The fact is, it isn't. If it were, it wouldn't **need** to be repeatedly explained by gurus to lesser mortals. I can't think of any other area of Python that needs to be defended so regularly and so vociferously, nor that very experienced Python programmers confess they find confusing. Swelp me, someone in this very thread (Barry) misunderstood it[1]. And suggesting that those of us who don't find it clear lack skill in English is just plain insulting. YMMV, but the only way I can grok it when I see it is to mentally translate "else" to "if no break". This is mental effort that would be spared or at least diminished if it were spelt in a more obvious way in the first place. Best wishes Rob Cliffe [1] or at least I think he did, I had trouble understanding him.

On Fri, 24 Jul 2020 at 02:18, Rob Cliffe via Python-ideas <python-ideas@python.org> wrote:
The upholders of the status quo regularly provide gallant explanations of why "else" is perfectly natural, even intuitive. The fact is, it isn't. If it were, it wouldn't *need* to be repeatedly explained by gurus to lesser mortals.
Fair point. It needs to be learned and remembered. It's not intuitive.
YMMV, but the only way I can grok it when I see it is to mentally translate "else" to "if no break". This is mental effort that would be spared or at least diminished if it were spelt in a more obvious way in the first place.
Again, probably true. With hindsight, if we were designing Python from scratch now, we'd probably not spell this as "else". We'd probably omit it altogether rather than using an alternative spelling, but that's a side issue. BUT - we're not designing Python now. The "else" clause on loops has been around for many years. It's in books, training courses and in existing, working code. We can't break all of that without a fairly large cost. And (as I've noted before) having *two* ways of writing this obscure construct would be even more confusing, particularly as people working with existing code or learning from existing training materials will naturally see the (presumably less intuitive and obvious) "else" spelling. So even accepting all of your points above, it's still very unlikely this will change. Not because there's no benefit, but because the cost is too high. Paul

On Thu, Jul 23, 2020, 9:19 PM Rob Cliffe via Python-ideas
I have used Python for 22 years, and I still cannot remember what else does in a loop for more than a few minutes at a time. It's easy to remember "it has something to do with whether there was a break." But neither direction in that choice yet feels obvious to me. I've read all the posts in this thread. I watched Raymond's explanation from a talk a few years ago. I've read Guido's explanation. I've read Knuth. I have a graduate degree in humanities and am a professional writer. I'm a native English speaker. It's still not intuitive to me. In my own code I just avoid the construct. I reckon I'm +1 on "some better spelling" ... although I manage fine without using it. I rarely see it in the wild, probably because it is confusing. I can't think of any other area of Python that needs to be defended so

To avoid the ambiguity of if after for why not follow for with elif? for x in ...: ... elif break: # break was called elif not break: # looped at least once and break not used elif pass: # same as else today # loop'ed no times (I always have to think what else means after a for). Barry

how about: for something in some_iterable: some_stuff_with_maybe_a_break else if not break: something_more No new keywords :-) or: for something in some_iterable: some_stuff_with_maybe_a_break else: # if not break: something_more and no changes needed to Python! I may actually start doing that myself ... As for the "loop didn't run at all" case: Does anyone find a need for that? Personally, I've found that everytime I do some kind of check for an empty iterable before a loop, it was totally unnecessary. A for loop means: "Do this stuff to all the items in this iterable." Most of the time, if there's nothing there, you don't need to do the stuff, and that's that. -CHB On Tue, Jul 21, 2020 at 5:28 PM Ethan Furman <ethan@stoneleaf.us> wrote:
-- Christopher Barker, PhD Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython

Hello, On Tue, 21 Jul 2020 17:48:35 -0700 Christopher Barker <pythonchb@gmail.com> wrote:
This is the most genius solution posted to this thread. And if the thread didn't die after van Rossum's post, I don't cheer hopes it would die now, but let me sprinkle in another "fresh" thought. First let me remind how this thread started:
ELSE-clause in FOR and WHILE has unclear syntax. I suggest new clause instead
Then various people started to throw in variants of even more unclear and confusing syntax (like "if" after "for"), with some percentage of those people demonstrating not understanding how the original "else" works. But consider following idea: if it's confusing, DO NOT USE it. You don't hear that often, but: treat Python as a generic programming language, not as a bag of tricks. The fact that most other languages don't have extra clause after "for" is enough of a reason to not use it in Python either. So why it exists at all then? It's there for people who don't find it confusing, for very responsible use. As a random example, after studying 2 (bytecode) Python compilers and having written my own (so I know what code is generated from for-else), I no longer find it confusing. I actually found 2 intuitive ways to use that construct, in the very compiler mentioned - after all, if you eyeball a Python compiler, you either know, or ready to learn, how all language constructs work. For anything else - clear ban. Everyone should consider that too. (But please leave the language syntax alone (backwards compatibility, etc.), at least that's a suggestion which comes out from van Rossum's post).
I find the need for that regularly. And I use the obvious syntax which everyone else uses: if not seq: print("This page is intentionally left blank") else: for i in seq: ... Any adhoc, confusing syntax someone may imagine to add, would go to the same "DO NOT USE" category. So, I pray to van Rossum's answer that something like that will never be added to the language. (Which is hard to hang hopes on, given all the mess added recently.) [] -- Best regards, Paul mailto:pmiscml@gmail.com

Not so easy for an iterator though. I’m more likely to do something like this: Page = NewPage() For content in iterable: Page.Add_stuff(content) If not Page: print("This page is intentionally left blank") (Sorry For the non PEP8 compliant capitalization— damn phone) -CHB
--
Christopher Barker, PhD Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython

On Wed, 22 Jul 2020 at 04:47, Paul Sokolovsky <pmiscml@gmail.com> wrote:
Frankly, saying that a part of a language that is frequently misunderstood, is *never* allowed to be improved is disappointing when the suggestion that it can be (somehow) has been so well received by everyone else.
Many people offering approaches is not muddling the thread. Clearly, most people here agree that `for...else` is confusing/unintuitive on it's own, and could be improved (not removed, but improved). The discussion was trying to find an improvement that people agree on as well. The reason there are so many offerings, is probably because everyone has had a similar thought about it in the past. -- Notice: This email is confidential and may contain copyright material of members of the Ocado Group. Opinions and views expressed in this message may not necessarily reflect the opinions and views of the members of the Ocado Group. If you are not the intended recipient, please notify us immediately and delete all copies of this message. Please note that it is your responsibility to scan this message for viruses. References to the "Ocado Group" are to Ocado Group plc (registered in England and Wales with number 7098618) and its subsidiary undertakings (as that expression is defined in the Companies Act 2006) from time to time. The registered office of Ocado Group plc is Buildings One & Two, Trident Place, Mosquito Way, Hatfield, Hertfordshire, AL10 9UL.

I'm (weakly) +1 for the concept of for..else being confusing, weird, and somehow not quite suitable/useful for many use-cases where it feels like it should. I'm -1 for each of the suggested improvements that I've understood so far. I agree that the suggested 'ban' on changes in this area is probably not helpful, however it feels like a sloppy way of saying that changes to the syntax are very unlikely to be practical, for a couple of annoying, but important reasons. The: for: ... else: # if not break: ... Solution seems to highlight this. The proposed convention of using comments here is clearly elective (nothing changes if you don't include the comment, although a style checker could require it, which would be a nice way of catching possible indentation errors) Because this is implemented as a comment, and thus optional, it feels pointless because the original confusion is still there for people who don't bother to add the comment, and less experienced coders are less likely to know about the convention. BUT it's probably as good as any other changes because... I don't feel that, on balance, the cost of making a breaking syntax change to the language (having worked on huge python codebases, the cost of any breaking syntax change is just massive) is justified here, so whatever improvements may be made would probably have to still support the old syntax as-is. The moment we retain the old syntax, then the new syntax becomes optional, and we're back in the problems with the comment approach. The only route I can see to a workable outcome here is to implement the: "else if not break:" clause as an optional alternate syntax, and update all the documentation to recommend using the new syntax over the old one (effectively silently deprecate for:...else:... syntax, but retain it indefinitely). But this has issues, because some people will still use the old syntax, so we'll end up with lots of code out there using both variants, and that's as likely to add to the general confusion here as reduce it. Steve On Wed, Jul 22, 2020 at 9:26 AM Mathew Elman <mathew.elman@ocado.com> wrote:

On Wed, 22 Jul 2020 at 10:54, Stestagg <stestagg@gmail.com> wrote:
I agree that for/while..else is not immediately obvious. But it's useful in some situations, and it *is* used in real-world code. I also agree that all of the proposals I've seen so far are at *least* as confusing, and would make the situation worse, not better. Generalising a bit, proposals that suggest *removing* else on loops are never going to get accepted, because they break existing code for no clear advantage. Ones that retain else on loops are bad because they end up providing two (typically equally confusing) ways of doing things. I don't think there's going to be any sort of "ban" on changing things, but I do think that it's reasonable to point out to people that all of this discussion is a waste of energy, and a distraction for people trying to follow this list for proposals that *do* have a chance of acceptance. The signal to noise ratio on this list can be bad at the best of times, and dropping ideas that simply won't work would help everyone. That's not to say that ideas that won't work aren't welcome - how will anyone learn what's feasible and what isn't if we shut down well-intentioned proposals? But proposers (and other participants) also need to accept that pushing an idea that isn't workable, is unproductive. Paul

On Wed, 22 Jul 2020 at 12:24, Paul Moore <p.f.moore@gmail.com> wrote:
agreed.
again, agreed.
I don't think this is the case. I agree that adding an alternative to `else` just to have an alternative is not a good fix, but adding explicit ways to refer to when breaking from the loop would make the use of `else` as it already is clearer. For example, breaking the change into 2 parts: 1. Adding `elif` to the `for...else` and `while...else` statements seems a logical extension. Guido has even said that the else in loops was invented by reasoning the connection of `if` to `while` (and then `while` to `for`). Perhaps this should be in its own discussion so as not to clutter this thread? 2. Adding a way to use this new `elif` to check the state of the loop. Possibly including if it was broken out of or if it was never entered. Such as having special local variables that are only defined in the block/frame of the loop.
I agree with you here too, 100%, but it does not feel like we have had said discussion. I would also make the suggestion that surely this thread, although noisey, is the right place to continue the discussion in case a consensus on an approach is reached. -- Notice: This email is confidential and may contain copyright material of members of the Ocado Group. Opinions and views expressed in this message may not necessarily reflect the opinions and views of the members of the Ocado Group. If you are not the intended recipient, please notify us immediately and delete all copies of this message. Please note that it is your responsibility to scan this message for viruses. References to the "Ocado Group" are to Ocado Group plc (registered in England and Wales with number 7098618) and its subsidiary undertakings (as that expression is defined in the Companies Act 2006) from time to time. The registered office of Ocado Group plc is Buildings One & Two, Trident Place, Mosquito Way, Hatfield, Hertfordshire, AL10 9UL.

On Wed, 22 Jul 2020 at 13:18, Mathew Elman <mathew.elman@ocado.com> wrote:
IMO, allowing for ... elif x == 2: do something to mean "if we didn't break out of the loop, and x is 2" would be really confusing. And to have the elif after a loop be limited to a different set of conditions than "ordinary" elif would *also* be really confusing.
2. Adding a way to use this new `elif` to check the state of the loop. Possibly including if it was broken out of or if it was never entered. Such as having special local variables that are only defined in the block/frame of the loop.
Same logic here - if we allow "elif not break" (for example), it would be really confusing to *arbitrarily* only allow that if the elif is attached to a loop. So we need to define what if x == 2: do something elif not break: what? means in general code. And that means inventing rules for the scope of "break as an expression". And in a similar vein, what does it mean to pass "break" to a function? def invert(flag): return not flag for ... elif invert(break): ... It's not that any of these things are *reasonable* to do, it's that all the special cases needed to disallow them would be confusing, and if we *didn't* disallow them, all of the rules needed to give them meaning in (conceded) unreasonable places would be confusing. The trick here is *not* to look at the case that you expect the construct to be used in - obviously it'll look good to you in that context, if you like the idea at all. What you need to look at is all the other ways it could be applied, and verify that the costs justify the improvement that you saw when you first encountered the idea. Paul

On Wed, 22 Jul 2020 at 13:45, Paul Moore <p.f.moore@gmail.com> wrote:
I don't think this would be any more confusing than `for...else` already is, and `while...elif...else` still seems like a logical extension of `while...else`. x=0 while x < 10: delta = get_delta(x) if delta == 0: break x += delta elif x%2: print(f"{x} is odd and > 10") else: print(f"{x} is even and > 10")
Absolutely! I would not suggest limiting it to any special cases. Hence why I split up the change. Adding a way to *also* use the elif to check the state of the loop is a separate discussion. Be that by using `break` as a special boolean or some other way.
means in general code. And that means inventing rules for the scope of
"break as an expression".
And in a similar vein, what does it mean to
That is fair enough, like I have said I am not attached (though others may be) to the idea of using `break` as a special boolean. Would it be more feasible to have a variable that persists beyond the scope of the loop and is not `break` but something else? For example, and this is not 100% serious but something like : `iter.broken`, `iter.enetered` etc.
Good point, I think this is a well made argument for *not* making `break` have a second meaning. -- Notice: This email is confidential and may contain copyright material of members of the Ocado Group. Opinions and views expressed in this message may not necessarily reflect the opinions and views of the members of the Ocado Group. If you are not the intended recipient, please notify us immediately and delete all copies of this message. Please note that it is your responsibility to scan this message for viruses. References to the "Ocado Group" are to Ocado Group plc (registered in England and Wales with number 7098618) and its subsidiary undertakings (as that expression is defined in the Companies Act 2006) from time to time. The registered office of Ocado Group plc is Buildings One & Two, Trident Place, Mosquito Way, Hatfield, Hertfordshire, AL10 9UL.

Hello, Why not just use Raymond's suggestion nobreak as a replacement of the else in loops and deprecate the else in Python 4? There is at least a precedent when not equal <> was deprecated in favor of != from Py2 to Py3. We could do the same with else/nobreak between Py3 and Py4. João Matos On 22/07/2020 14:36, Mathew Elman wrote:

On Thu, Jul 23, 2020 at 7:06 AM João Matos <jcrmatos@gmail.com> wrote:
Py2 supported both <> and !=, so code could be completely compatible with both branches just by using !=. You're proposing creating a new way of doing things and then deprecating or removing one of them, which either means there'll be two identical spellings, or you break everyone's code (or both). It's almost the opposite of the <> change. Please, everyone, can we NOT keep coming up with ideas that are basically "let's invent a new spelling for exactly the same thing, with no benefits, and demanding new keywords, so we can break people's code for no reason"? You can always just write your own transpiler to let yourself spell it your preferred way. ChrisA

On Thu, Jul 23, 2020 at 07:22:51AM +1000, Chris Angelico wrote:
Surely having a less confusing and misleading spelling is a benefit. We like to use Python because its syntax is so readable and obvious. "for...else" is a wart on the language, it is a lovely feature marred by a confusing keyword. The long term benefit is to reduce that confusion. We have heard from people in this thread that they reject for...else in code reviews because it is too confusing. The question to me is not "Why make this change for no benefit?" but "Is the benefit sufficient to go through the pain of change?". Guido seems to be open to the use of *soft keywords* now that CPython has moved to a PEG parser. Perhaps we could introduce a soft keyword as an alternative spelling for "else": for x in sequence: ... then: # allow the bike-shedding to begin :-( ... Being a soft keyword, outside of that context it will remain legal, so no-one needs to rename their "then" methods or variables. Code using "for...else" remains legal, although linters might warn against it. We need not actually depreciate the use of "else", not unless we plan to reintroduce it with a different meaning. But that's a separate discussion. So here's a concrete proposal: (1) `for...else` and `while...else` stay, for backwards compatibility. (2) Add a soft keyword "then" (bikeshed away...) to use in for and while loops, as an alternative preferred spelling to "else". (3) Update PEP 8 to make it clear that new code should use `for...then` and `while...then` rather than "else". (Old code need not change just for the sake of changing it.) (4) Linters and style-checkers can prefer `then`, but the interpreter itself will remain neutral and accept both. To avoid all doubt: (5) There is no plan to depreciate the hard keyword `else`, not even a PendingDepreciation warning. (6) Any suggestion that we repurpose `for...else` to mean "run this if the loop is empty" will have to justify itself. It is not part of this proposal. It seems to me that this is a pretty minor change, with little downside, that could have a big effect on the readability and usefulness of what's currently spelled as `for...else` and underused because people find it confusing. Compared to the benefits, the downsides are small: - Someone has to do the work. That's a one-off cost. - Double the tests: we have to verify `for...else` and `for...then` both work. This is a pretty small cost. - Two ways to do it. Despite the Zen, there are two ways to do many things in Python. But this is a pure alias: for...then and for...else are literally compiled to the same code. The Zen should be understood as *food for thought* not unbreakable rules of nature. If we accept this proposal, we could interpret it as follows: * the One Way to do it is `for...then`; * but for backwards compatibility there's also an alternative spelling that we prefer not to talk about, see the docs if you care. There are no runtime costs. The compiler should generate the exact same bytecode for the two spellings. There's no breaking backwards compatibility, as `then:` followed by a block is not currently legal. If `then` is a soft keyword, existing uses of "then" won't be affected.
How do I do that? That's not a rhetorical question. I keep wanting to study projects like LikePython for hints, because I am sick of *Old Man Python* telling me what I can and can't write, but somehow never find the time. https://jon.how/likepython/ If we had some sort of easy to use standard library support for transpiling code, then your advice could actually be practical and not just dismissive. "Pft, if you don't like it, write your own language" is not exactly practical for most people. Even if a transpiler is a tad simpler than writing an entire interpreter or compiler, it's still a new language. -- Steven

On Sat, Jul 25, 2020 at 11:13 AM Steven D'Aprano <steve@pearwood.info> wrote:
Minor, given that the existing spelling still has to be supported. Now you have two ways to do it, for the foreseeable future, and only style guides will differentiate. And a lot of style guides will say "prefer else because it's compatible with more Python versions". How long will it be before you can actually take advantage of it?
I don't dispute that, but that's very long term benefit, with a lot of short and medium term costs. The concept is a bit unusual (I don't know many other languages that support this with *any* spelling), so it still has to be explained, and a lot of people will still be confused no matter how you spell it. How much benefit do you actually gain?
That's a notable reduction in cost (and an improvement in flexibility for the bikeshedding - although that will, of course, mean that the bikeshedding takes ten times longer!), but the cost of creating a second way to do things isn't just the creation of the keyword.
Linters and style checkers will have to choose whether to recommend the "better" spelling (unquantifiable benefit) or the one that runs on more versions of Python (concrete, meaningful benefit).
I hope nobody EVER proposes that. Having code that means different things on different Python versions would be an absolute pest to work with. But if all the prior objections are overcome and "for... then" gains currency, there'd be some reasonable grounds for proposing a completely different keyword to have the "if loop is empty" semantics.
And all your documentation, examples, etc, have to care.
It depends how smart you want it to be. If you literally just search and replace "then:" into "else:" without caring about context, it'd be trivially easy. Obviously that's pretty risky, but adding a check for string literals would probably cover most normal code. Actually doing the job properly...
... would be best done with stdlib support, yes. I think import hooks can do everything that's needed, but I've never actually done it. Normally I'd just use a simple source-to-source transformation before execution, and usually I do things that aren't ever going to show up (string literals aside), so I don't need it to be very smart. ChrisA

On Fri, Jul 24, 2020 at 10:43 PM Chris Angelico <rosuav@gmail.com> wrote: SNIP
Already done (with a different keyword): https://aroberge.github.io/ideas/docs/html/nobreak.html André Roberge

On Sat, Jul 25, 2020 at 12:09 PM André Roberge <andre.roberge@gmail.com> wrote:
Thank you. Especially since the source code is extremely short: https://github.com/aroberge/ideas/blob/master/ideas/examples/nobreak.py I'd like to see this 'ideas' module (or similar) better known. It'd help a lot with complaints like Steven's. ChrisA

On Sat, Jul 25, 2020 at 12:49:36PM +1000, Chris Angelico wrote:
On Sat, Jul 25, 2020 at 12:09 PM André Roberge <andre.roberge@gmail.com> wrote:
Already done (with a different keyword):
That's a very nice project André, and I think it will probably useful for playing around with experimental new syntax. [Chris]
Before telling people to use the ideas module, perhaps you ought to read the IAQs: https://aroberge.github.io/ideas/docs/html/#infrequently-asked-questions-and... These sorts of hacks may be great for experimentation, but if people are so conservative that they reject an actual language feature, `for...else`, in code reviews, do you really think they're going to use `ideas` in production? I fear that even if we could get the average developer to say "I know, let's use `ideas` to write a DSL", the project manager -- and the rest of the team -- will probably respond "Over my dead body". We're a long, long way from this sort of thing being considered acceptable in production code. -- Steven

Hello, On Sat, 25 Jul 2020 18:44:55 +1000 Steven D'Aprano <steve@pearwood.info> wrote: []
You seem to mix up Python with some other language, perhaps Java. Its usecase dictate being used with "project managers" attached. I myself and I'm sure many other people use Python in settings which don't involve external project managers. Actually, we use Python exactly because it's possible to make useful projects using it without involvement of dedicated project managers, because Python is expressive and high-level language. And if expressiveness can be improved using custom syntax macros, etc., we'd like to be able to do it. If your recent idea, the "then:" keyword is based on "project managers" usecase, then... well, please disclose that fact. I personally don't appreciate adding confusing duplicate features to the core language to make "project managers" happy. But then again, in any professional, commercial setting any adhoc-semantics keyword for loops would be disallowed in the first place, no matter how it's called. That's because any Python project may be tomorrow rewritten in Java, day after in Go, etc. And as none of these languages (or most of others) have any such adhoc semantics for loops, neither it should be used in Python.
-- Steven
-- Best regards, Paul mailto:pmiscml@gmail.com

On Sat, Jul 25, 2020 at 11:40:06AM +1000, Chris Angelico wrote:
And a lot of style guides will say "prefer else because it's compatible with more Python versions".
Like they did in Python 2 when we had two ways of getting the next element from an iterator? # Python 2.7 py> it = iter([1, 2]) py> next(it) 1 py> it.next() 2 How many style guides said "Prefer the next *method*, because more Python versions (Python 2.2 on up) support it"? If there were any at all, they were a microscopic proportion of the ones that used the preferred next *function*, because that's what the std lib and documentation said to use. If the docs and PEP 8 says the soft-keyword "then" is preferred, the number of people who will stick to the "else" keyword a single day longer than they need to for backwards compatibility will rapidly drop to zero.
How long will it be before you can actually take advantage of it?
Of course libraries that need to support older versions of the language will have to use the old form, but that applies to *every* new feature. How many libraries that support Python 3.3 or 3.5 are using the walrus operator? Zero. Therefore we shouldn't have added the walrus operator, right? As the author of the walrus PEP, I'm sure you recognise that this sort of argument is weak. When we add new syntactic features we're looking forward to the future. Not everyone can be an early adopter using the cutting edge version with the latest features, but on the other hand most people aren't stuck forever supporting Python 3.3 (or 1.5) either. Some people will be able to use it the moment the feature is checked into the source repo. Some people won't be able to use it until 2040. And the majority will start to use it within a year or two. Like any other new language feature. [...]
And all your documentation, examples, etc, have to care.
Of course there will be a transition period where people say "I tried to run for...then and got a syntax error", but that doesn't last forever. When is the last time you've seen someone asking about syntax errors from `with` statements? Or async and await, for a more recent addition to the language? Look at PEP 530: https://www.python.org/dev/peps/pep-0530/ This PEP added a second way to do it: # Old Way, necessary before 3.6 result = [] async for i in aiter(): if i % 2: result.append(i) # New Way, only valid from 3.6 onwards result = [i async for i in aiter() if i % 2] If I were to go to StackOverflow, or Python-List, and ask "How do I run a list comprehension asyncronously?" how many people would give the Old Way? Would you? Of course the official docs have to document that "for...else" is accepted by the compiler and translated into "for...then", for backwards compatibility; and old documentation won't change. But new documentation would rapidly change to preferring the new version and not even mentioning the old version except maybe as a curio of the language. Who remembers using the Decorate-Sort-Undecorate idiom in Python? It was *everywhere*. Then we got a key function parameter, and seemingly overnight the DSU idiom just disappeared. -- Steven

On Sat, Jul 25, 2020 at 7:18 PM Steven D'Aprano <steve@pearwood.info> wrote:
I've no idea. When did the next() function come in, and what was it like while older versions than it were still current? Looking *now* isn't indicative.
Of course, but it IS an argument. The walrus operator gives new expressiveness. Async/await has a massive advantage over manually doing your wait points. The "but you can't use it yet" argument is a lot weaker than "it makes your code way cleaner", but the argument in favour of the current proposal is "it's a better choice of words". I don't dispute that it would be an improvement. I just dispute that it's enough of an improvement to create a new spelling for something that has no other advantage. Do you REALLY think that everyone will automatically understand it just because it's spelled "for... then" instead of "for... else"? ChrisA

On 7/25/2020 7:28 AM, Chris Angelico wrote:
Do you REALLY think that everyone will automatically understand it just because it's spelled "for... then" instead of "for... else"?
I wouldn't find "for ... then" any less confusing than "for ... else". I do find "for ... else if not break" easier to understand, but I'm not convinced its worth the hassle over "for ... else # if not break". Four keywords in a row! But all of these always make me wonder about a return inside the suite. Does the "else" part execute (answer: no). So as a rule, I avoid the construct entirely, not that it comes up very often, anyway. Eric

On Sat, Jul 25, 2020 at 4:39 AM Eric V. Smith <eric@trueblade.com> wrote:
I'm pretty sure that the OP on this proposed "then" as a placeholder, with the final choice of word to be determined. But I do think this is pretty darn illustrative --'cause I would find "then" even LESS intuitive, and it's a whole new keyword to boot! I'm one of those folks that have been around Python for a long time -- starting with 1.5 -- and I still find for-else a bit confusing, but I remember that it exists, so go figure it out when I need it. And that is not very often. Frankly, it's a nifty feature, but it's still not a very common use case -- so It's just not a very clear win to spell it better. And as the "then" example shows, it's really hard to find a better spelling -- it's just not that common a construct in programming languages, and it's not used that often in Python -- if it were, I"d probably remember what it meant :-)
well, there are two sides to usability: 1) Remembering it's there, and how to use it when you are writing code, which I think is not such a big deal -- if you remember its there, you can figure out how to use it. And if you don't remember it's there, then a better spelling isn't going to help. 2) understanding what it means when you are reading code -- and that, a better spelling would help with. But I don't get folks that would reject it in a code review -- I'd just suggest that you add a # if not break comment -- or better yet a comment that describes why it's there in the context of that problem -- as comments are supposed to do. Would you really as someone to replace: for dodad in all_the_things: if dodad == something_special: found_special_dodad = True break do_things_with(dodad) else: # the special one wasn't there -- need to process the stuff process(stuff) with this?: found_special_dodad = False for dodad in all_the_things: if dodad == something_special: found_special_dodad = True break do_things_with(dodad) ... if not found_special_dodad: # the special one wasn't there -- need to process the stuff process(stuff) The for--else construct exists for a reason: it's much cleaner than creating a flag and checking it later. Sure it would be nicer if it had a better spelling, but else # not break is pretty easy if you want to make your code more readable and there isn't need for an explanatory comment otherwise. I'm not advocating for any change (Obviously :-) ) -- but if there were to be one, I"d strongly vote for some version of else not break or else if not break because it introduces no keywords, and it's a lot more compatible documentation-wise than a different word -- it's almost like a built-in commnet :-) By that I mean that folks that see the two different spellings in two different tutorials or SO answers ,or whatever, are more likely to realize that they mean the same thing. But all of these always make me wonder about a return inside the suite.
Does the "else" part execute (answer: no). So as a rule, I avoid the construct entirely,
really? does an if-else clause execute if there's a return in the if? no. why would this be any more confusing?
not that it comes up very often, anyway.
This is the really key point. I wanted to use a real code example above, but I could not remember when I'd ever used it -- and it's hard to search for, so I couldn't find one. So: churn to make something rarely needed a little bit better -- I don't see the point. -CHB -- Christopher Barker, PhD Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython

On Sat, Jul 25, 2020, 3:12 PM Christopher Barker
As bikesheds go, I like a "soft keyword" which PEG apparently makes easier. Maybe 'nobreak' or 'notbreak' or 'finished'. But as Christopher notes, the spelling 'else: # not break' is fine for readability, even if not for remembering it.

On 7/25/2020 3:11 PM, Christopher Barker wrote:
Because I always remember "for ... else" has something to do with leaving the loop early, but I don't recall if it's more like try ... finally, or if it's related to the loop exiting early, or the loop not exiting early, or something else I can't recall. So, the answer to your "really?" question is "yes". Eric

How about we just document the whole feature as deprecated and never speak of it again? -- Greg

Mathew Elman writes:
The highly improbable is frequently well-received. What can surely be improved is the documentation, specifically the Tutorial. Something like The else clause of a loop statement has frequently been misunderstood. In a for or while loop *statement*, on each iteration, the condition is tested and exactly one of the following occurs: 1. If truthy, the loop *suite* runs to completion and the test is repeated for the next iteration, 2. OR the loop *suite* runs and there is a nonlocal exit such as return or break or raise, which exits the statement as well. 3. OTHERWISE the condition is false, and the else suite, if any, runs, then the statement is exited. The emphasis is for contrast in this discussion. The Language Reference already says precisely this, although much more concisely. I don't expect supporters of "elif not break" etc to think this is sufficient, and supporters of the Else Ban similarly. Please consider if this is helps clarify the Tutorial, and if it doesn't get booed into oblivion, I'll work up a patch (I think that the section on control flow would benefit from some reorganization as well, "just stick it in somewhere" is not what I have in mind :-). Steve

On Thu, 23 Jul 2020 at 16:25, Stephen J. Turnbull < turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:
Credit where credit is due, I think this is definitely an improvement. It does make it require slightly less meticulous reading to understand `else`. However, I still think that there is value in improving the `for...else` and `while...else` intuitiveness, if it can be done at an acceptable cost. (As is the case with any change) IMO the solution is not to change `else` but to add an additional with the opposite meaning that makes the use of `else` with `for` and `while` more intuitive, such as adding `elif`, which feels natural, and a special boolean, which perhaps doesn't. Or adding `except` for catching raised Exceptions rather than breaks, which makes `else` clearly behave how it does for `try`. Or another solution that achieves the additional clarity *without* removing/changing else itself.
Steve
-- Notice: This email is confidential and may contain copyright material of members of the Ocado Group. Opinions and views expressed in this message may not necessarily reflect the opinions and views of the members of the Ocado Group. If you are not the intended recipient, please notify us immediately and delete all copies of this message. Please note that it is your responsibility to scan this message for viruses. References to the "Ocado Group" are to Ocado Group plc (registered in England and Wales with number 7098618) and its subsidiary undertakings (as that expression is defined in the Companies Act 2006) from time to time. The registered office of Ocado Group plc is Buildings One & Two, Trident Place, Mosquito Way, Hatfield, Hertfordshire, AL10 9UL.

On Tue, Jul 21, 2020 at 05:48:35PM -0700, Christopher Barker wrote:
I always do that, not because I need it now, but because the next person who reads my code in six months might need it. That person might even be me.
If we had it, I would use it. It is generally possible to work around the lack, e.g. with an explicit test of a sequence (but that doesn't work with iterators), but I find that sometimes it isn't *obvious* that the empty loop case is handled correctly: for x in iterable: do stuff continue processing If iterable is empty, is the code still correct? Sometimes that's obvious, but when it *isn't* obvious I wish there was a way to run this: for x in iterable: do stuff if loop was empty: whatever is needed to make it obviously correct such as an assert, or early return I'd rather have an extra couple of lines of code and obviously correct code than save a few lines and have to think hard about whether the code is correct :-) More rarely I do need to treat the empty case specially. If the iterator is a sequence I can test the length up front, but this doesn't work with iterables. It's not *hard* to work around this, it's just inelegant. -- Steven

On 20/07/2020 09:56, Alex Hall wrote:
But detecting the number of iterations (however it's spelt) might be tricky. Always counting the number of iterations would slow down *every* for/while loop - surely unacceptable. So the compilation process must only incorporate this loop-counting when the loop is followed (after 100 lines of code??) by a reference to the loop count. Another way would be for the first iteration (i.e. the first call of `next') to be coded separately (in the bytecode). If the first call does not raise StopIteration, it could set a flag meaning "at least 1 iteration occurred", But this would bloat the code, and again doesn't seem like a great idea if it applies to *every* for/while loop. Therefore: I suggest that the proposal should be modified to just detect break or no break. That's already progress. And if in future someone thinks of a brilliant way of detecting zero (or N) iterations, that can be added later.

I don't know what to do about the zero iterations case, though. Perhaps simply `if not:' Best wishes Rob Cliffe

On Wed, Jul 15, 2020 at 05:45:05AM +0000, Steve Barnes wrote:
Sorry Steve, "finally" would be a terrible name because it behaves nothing like try...finally. In try blocks, the finally block is *always* executed, even if you raise, even if you return. (To be precise, there are odd and unusual cases where finally won't be executed, such as if the interpreter process is `kill -9`'ed, or if a power surge fries the CPU. But under normal processing, finally always runs.) But the for...finally (renamed from for...else) is not like that. If anything, it's the opposite of finally: it is a block designed to be skipped, not a block designed to always run. Any of `break`, `return` or `raise` will cause the for...finally clause to be skipped. So we would be swapping one form of confusion to another ("why is my finally clause not executed?"). -- Steven

Thank to all disputants. It is possible to borrow the keyword "case" from PEP-622 (when it appears https://www.python.org/dev/peps/pep-0622). Keyword "case" can be written instead of "else/elif". I.e. case COND: ... [case COND: ...] [case COND: ...] All conditions COND must be different. Last "case COND:" can be replaced with "else:".

On Sun, 19 Jul 2020 at 15:43, Олег Комлев <ar12wtz@gmail.com> wrote:
For me this is -1 because "for... case" and "while... case" don't read like english. I also think the issue is less what keyword is used from "case", "if", "except" or "joojoo" rather what the "COND" look like. Obviously this depends on what the keyword is e.g. for "case"/"if" they should be predicates, for "except" they should be exceptions and if adding a new keyword it may be they are not needed. But I would say deciding on those is the priority. Side Note: It does feel like "elif" should be part of the "for-else" and "while-else" (especially while) compound statements. -- Notice: This email is confidential and may contain copyright material of members of the Ocado Group. Opinions and views expressed in this message may not necessarily reflect the opinions and views of the members of the Ocado Group. If you are not the intended recipient, please notify us immediately and delete all copies of this message. Please note that it is your responsibility to scan this message for viruses. References to the "Ocado Group" are to Ocado Group plc (registered in England and Wales with number 7098618) and its subsidiary undertakings (as that expression is defined in the Companies Act 2006) from time to time. The registered office of Ocado Group plc is Buildings One & Two, Trident Place, Mosquito Way, Hatfield, Hertfordshire, AL10 9UL.

On 11/07/2020 06:22, Олег Комлев wrote:
Just to spell it out: If I understand you correctly, you are proposing that after a 'for'/'while' loop 'if break:' has its intuitive meaning: "if the loop was terminated with a 'break'". 'if finally:' means "if the loop completed (possibly with zero iterations) *without* a 'break'" (equivalent to 'else' at present). 'if pass:' means "if there were zero iterations of the loop (obviously, without a 'break')" (I assume that a partial iteration terminated by 'continue' would count as an iteration) plus 'elif' when you want to handle more than one of the above. So if COND1: ... elif COND2: ... would be legal, but if COND1: ... if COND2: ... would not. Something to consider: Would it be legal to mix these CONDs with other conditions in the 'elif' chain? E.g. if break: ... elif x > 0: ... elif finally: ... I would be the first to agree that the use of 'else' after 'for'/'while' is one of Python's more obscure features (I understand even veterans trip up over it). I like the general idea and I like 'if break:', but IMO the meanings of the other two are not obvious. I would suggest 'if not break:' rather than 'if finally:'. (And PEP 8 could recommend it rather than 'else:'. :-)) My gut feeling (backed by no evidence) is that dealing with the case of zero iterations is not needed frequently enough to cater for it. And I don't know if there is a good way to spell it (which might be another reason not to do it). Plus it's something which could be added later. Best wishes Rob Cliffe

On Sun, Jul 12, 2020, at 00:16, Rob Cliffe via Python-ideas wrote:
What if "instead of a special kind of if clause that can only be placed after a loop", we simply defined these three special expressions [usable in any if/elif statement] to reference special boolean flags that are set after exiting any loop?

On Tue, Jul 14, 2020, at 17:55, Rob Cliffe wrote:
Sorry if this was unclear, but my idea is that they would be per-frame like local variables. Perhaps they could even be implemented *as* local variables, with assign statements emitted during loops by the compiler if they are used anywhere in the function. If that violates 'local transparency', so does using the same scope for ordinary local variables [such as, say, the iteration variable of a for loop, which can also be used 100 lines of code later]. And of course PEP 8 would forbid using them anywhere other than directly after a loop, but allowing them to be used in any if clause prevents you from having two different kinds of compound statement, which can't be mixed together, that both begin with the word "if".

On 07/11/2020 09:16 PM, Rob Cliffe via Python-ideas wrote:
My gut feeling (backed by no evidence) is that dealing with the case of zero iterations is not needed frequently enough to cater for it.
My personal experience is that the case of no iterations is frequent enough, and a big enough pain to deal with, that if we're making changes we should include a way to deal with it. Currently: if empty_iterable: # do whatever else: for it in iterable: # do something or maybe: obj = object for obj in some_iterator: do_stuff() if obj is object: # iterator was empty do_different_stuff() Either way, for obj in iterator: do_stuff elif empty: do_other_stuff() would be much nicer. -- ~Ethan~

What about adding `except` to the compound loop statement? That way in cases where there needs to be clarity you can raise a specific exception rather than just `break`. Keeping the logic of why you "break" the loop inside the loop and would also allow multiple reasons for breaking from a for loop to remain clear. e.g.
On Tue, 14 Jul 2020 at 05:33, Ethan Furman <ethan@stoneleaf.us> wrote:
-- Notice: This email is confidential and may contain copyright material of members of the Ocado Group. Opinions and views expressed in this message may not necessarily reflect the opinions and views of the members of the Ocado Group. If you are not the intended recipient, please notify us immediately and delete all copies of this message. Please note that it is your responsibility to scan this message for viruses. References to the "Ocado Group" are to Ocado Group plc (registered in England and Wales with number 7098618) and its subsidiary undertakings (as that expression is defined in the Companies Act 2006) from time to time. The registered office of Ocado Group plc is Buildings One & Two, Trident Place, Mosquito Way, Hatfield, Hertfordshire, AL10 9UL.

On 14.07.20 09:54, Mathew Elman wrote:
That can be done already today by putting the `for` loop in the `try` body. Also here `else` should rather mean `did not raise` as for the normal `try/except/else` usage (and similar to how `for/else` means `did not break`). The more interesting part is to detect whether the loop did some work at all (i.e. whether the iterable was empty). But also this can be done with some small overhead: loop = Loop(iterable) for x in loop: pass if loop.empty: pass The `Loop` class here wraps the sentinel logic required to detect if the iterable was empty.

On Tue, 14 Jul 2020 at 12:38, Dominik Vilsmeier <dominik.vilsmeier@gmx.de> wrote:
It can, but my thought was that this would be sugar that made it easier to follow the logic
Yes sorry, I made an error. I confused myself about what else does, how ironic. This would be most useful for cases where break and not breaking were unclear.
The more interesting part is to detect whether the loop did some work at all (i.e. whether the iterable was empty).
This could be done by raising a "silent" exception that is handled by default (something like StopIteration), when trying to iterate an empty iterable. If the "NoIteration" exception is not caught explicitly it is ignored. Then you could have :
This may not be to everyone's taste, but to me it's better than the current state of things and clearer than having special if statements after a loop.
_______________________________________________
-- Notice: This email is confidential and may contain copyright material of members of the Ocado Group. Opinions and views expressed in this message may not necessarily reflect the opinions and views of the members of the Ocado Group. If you are not the intended recipient, please notify us immediately and delete all copies of this message. Please note that it is your responsibility to scan this message for viruses. References to the "Ocado Group" are to Ocado Group plc (registered in England and Wales with number 7098618) and its subsidiary undertakings (as that expression is defined in the Companies Act 2006) from time to time. The registered office of Ocado Group plc is Buildings One & Two, Trident Place, Mosquito Way, Hatfield, Hertfordshire, AL10 9UL.

Can I suggest that for loops the `else` would be a lot clearer if it was spelt `finally` as was done for PEP-0341 for try blocks and that we might possibly need one or more `on_…` clauses such as `on_break` and `on_finish` I think that this would be a lot clearer: for i in range(N): if i > 3: break; on_break: # Called if loop was broken print(i) on_finish: # Called if loop was not broken print("Loop Completed") finally: # Always called (replaces for…else) print("Loop Ended") Which I think would be a lot easier for newcomers to learn than try…for…else…except…else e.g.: try: for i in range(N): if i > 3: break; elif i % 2 == 0: raise ValueError("Odds Only"); else: # to if print(i) else: # Else to loop print("Loop Completed") except ValueError as err: print(err) else: # to try print("No Exception") finally: print("Try Ended") Where the multitude of elses makes my eyes cross. Steve Barnes

But in `for...else` the `else` call isn't always called, so changing `else` for `finally` doesn't make sense. What you're suggesting is replacing `else` with `on_finish` and adding `finally` and `on_break`. I agree that having `finally` could make the use cases of `else` clearer, but I am not convinced renaming "else" to "on_finish" would help the confusion for the 0 iteration case. I think that since this suggestion doesn't help with the 0 iteration case (my first idea here didn't either), it feels like added extra compound statements need to be immediately intuitive to be worth having - either because they read like a sentence or parallel existing python e.g. `try-except-else-finally` or `if-elif-else` etc. On Wed, 15 Jul 2020 at 06:47, Steve Barnes <GadgetSteve@live.co.uk> wrote:
-- Notice: This email is confidential and may contain copyright material of members of the Ocado Group. Opinions and views expressed in this message may not necessarily reflect the opinions and views of the members of the Ocado Group. If you are not the intended recipient, please notify us immediately and delete all copies of this message. Please note that it is your responsibility to scan this message for viruses. References to the "Ocado Group" are to Ocado Group plc (registered in England and Wales with number 7098618) and its subsidiary undertakings (as that expression is defined in the Companies Act 2006) from time to time. The registered office of Ocado Group plc is Buildings One & Two, Trident Place, Mosquito Way, Hatfield, Hertfordshire, AL10 9UL.

But `finally` with a `for` loop is redundant since the code can be placed just after the loop. For `try/except` it's a different situation since the exception might bubble up, so "normal" code after the `try` won't be reached. Also `on_break` doesn't seem really important since that code can be executed inside the loop right before the `break`. We already have `else` for `on_finish` and I think when recalling the analogy to exceptions it's not that confusing: a `try` block can be exited either normally (because all code has been executed) or because it raised an exception; here `else` means it exited normally. Similarly a `for` loop can terminate either normally by executing all iterations or because a `break` occurred; and similarly `else` means it terminated normally. On 15.07.20 08:47, Mathew Elman wrote:

The point is that `for-else` reads like "do this for loop ELSE (or but if you can't loop) do this", i.e. roughly equivalent to this:
or
But that isn't what it means. It means "do this for loop and if you deliberately break out, continue ELSE (or if you don't break out) do this". i.e. roughly equivalent to this:
or
pass
else:
print("you didn't break from the loop you maybe entered...")
which is not intuitive because `else` reads like it handles the unexpected case, which one would have guessed was either breaking out or not entering in the first place. On Wed, 15 Jul 2020 at 09:23, Dominik Vilsmeier <dominik.vilsmeier@gmx.de> wrote:
-- Notice: This email is confidential and may contain copyright material of members of the Ocado Group. Opinions and views expressed in this message may not necessarily reflect the opinions and views of the members of the Ocado Group. If you are not the intended recipient, please notify us immediately and delete all copies of this message. Please note that it is your responsibility to scan this message for viruses. References to the "Ocado Group" are to Ocado Group plc (registered in England and Wales with number 7098618) and its subsidiary undertakings (as that expression is defined in the Companies Act 2006) from time to time. The registered office of Ocado Group plc is Buildings One & Two, Trident Place, Mosquito Way, Hatfield, Hertfordshire, AL10 9UL.

I'm really glad that Олег Комлев has posted this suggestion to the list. Thank you! I found myself using this construction, and in December 2019 (that seems a long time ago) I discussed it face-to-face with Paul Piwek. He found this highly relevant article https://stackoverflow.com/questions/9979970/why-does-python-use-else-after-f... Here's a brief (and selective) summary of this SO page. The question was asked in 2012. The original poster wrote "No matter how I think about it, my brain can't progress seamlessly from the for statement to the else block." One of the answers references a talk by Raymond Hettinger, which "briefly addresses the history of for ... else". He attributes the concept to Don Knuth, and says that if Guido was thinking about the future he (GvR) would have called it no_break instead of else, so everyone would know what it did. I highly recommend that you watch RH's talk, 15:50 to 19:00 (min:sec). Transforming Code into Beautiful, Idiomatic Python https://www.youtube.com/watch?v=OSGv2VnC0go&feature=youtu.be&t=950 The Stackoverflow page also references a summary of earlier discussions that Steven D'Aprano kindly prepared and posted to this list (in 2009). https://mail.python.org/pipermail/python-ideas/2009-October/006155.html That's the end of my SO summary. In addition, there's Don Knuth's paper Structured Programming with goto statements (1974) Reprinted in https://www-cs-faculty.stanford.edu/~knuth/lp.html By the way, I happen to have a copy of this book (typeset by TeX, of course) and have more than once read the 1974 goto paper. (There we go. A loop with a break.) If you don't have ready access to a copy, you might like to look at http://people.cs.pitt.edu/~zhangyt/teaching/cs1621/goto.slides.pdf http://www.kohala.com/start/papers.others/knuth.dec74.html I think that's enough for now. And thank you again Олег, for posting your suggestion to the list. -- Jonathan

On 15/07/2020 09:20, Dominik Vilsmeier wrote:
+1
Also `on_break` doesn't seem really important since that code can be executed inside the loop right before the `break`.
Not true, because you might have multiple breaks. This would avoid putting the same code after each one. May I repeat: Spelling 'if break:' and 'if not break:' rather than say 'on_break:' etc. would avoid adding new keywords. I don't know what to do about the zero iterations case, though. Best wishes Rob Cliffe

On Mon, Jul 20, 2020 at 10:36 AM Rob Cliffe via Python-ideas < python-ideas@python.org> wrote:
It could be that if `break` appears somewhere that an expression is expected, it becomes an expression with the value 0 or 1 (or False or True) to indicate the number of breaks that happened in the previous loop, and similarly some other bit of code involving keywords can become the number of iterations of the previous loop. This could be represented by `for`, `len(for)`, `pass`, etc. So one might write: ``` for x in ...: ... if not pass: ... elif pass == 1: ... else: ... ```

This is a continuation of my previous post to this thread. Python's FOR ... ELSE ... , Raymond Hettinger has told us, has origins in some ideas of Don Knuth. For that reason, and others, I'll concisely review these ideas. In the very early days, a computer program was a sequence of commands. The goto <somewhere> command was used to create loops, and the IF command was used to break from loops. Often, this led to what was called spaghetti code. (In some versions of BASIC, the GOTO was to a line number.) In the 1960's ideas developed to remedy this situation. Edsger Dijkstra coined the phrase 'structured programming', and he was the author of the famous paper 'Go To Statement Considered Harmful'. (I recall reading that the title was supplied by Wirth.) Aside: This is in the context of source code. By 1970 there were higher level languages, which were compiled into machine code. Dijstraka I'm sure approved, within limits, of GOTO in machine code. One consequence of structured programming is to provide and guarantee such limits. Don Knuth's 1974 paper, Structured Programming with goto statements, finds merit in both sides of the question. One of his goals is "improved syntax for iterations and error exits, making it possible to write a larger class of programs clearly and efficiently without goto statements". Nearly done with the review. Knuth finds a result of Lipton, Eisenstadt and DeMillo especially noteworthy. Briefly, for every large n, there is an n-statement program using goto statements that cannot be 'nicely converted' to a structured program. By 'nicely converted' (my phrase) Knuth means that the structured program is either larger or slower or both than the goto program, with a numeric lower bound on by how much. (Size exponential in n, speed logarithmic in n, both with explicit constants.) This justifies Knuth's phrase "a larger class of programs" in the goal I just stated. Aside: Incidentally, Knuth's paper uses coroutines in his discussion of efficient implementation of Hoare's quicksort algorithm. In it he credits Strachey sharing with Knuth the importance of coroutines (or goto) for producing a conceptually simple solution to the problem of merging two binary trees. It might help if a tutorial on how to do this in Python, by using async and wait, was written. My next post will apply some of the concepts in Knuth's goto paper to FOR ... ELSE ... in Python. The above relies on a lot of implied knowledge. If you don't already have it, the above might be hard going. I hope it helps at least some of you. -- Jonathan

On Mon, Jul 20, 2020 at 03:22 Jonathan Fine <jfine2358@gmail.com> wrote:
That’s news to me (both that it’s due to Knuth and that Raymond said so). I invented it without awareness of prior art, by reasoning about the similarity between IF and WHILE (FOR followed from WHILE). —Guido -- --Guido (mobile)

On Mon, Jul 20, 2020 at 03:22 Jonathan Fine <jfine2358@gmail.com <mailto:jfine2358@gmail.com>> wrote: This is a continuation of my previous post to this thread. Python's FOR ... ELSE ... , Raymond Hettinger has told us, has origins in some ideas of Don Knuth. That’s news to me (both that it’s due to Knuth and that Raymond said so). I invented it without awareness of prior art, by reasoning about the similarity between IF and WHILE (FOR followed from WHILE). —Guido See Raymond's video "Transforming Code into Beautiful, Idiomatic Python" at https://www.youtube.com/watch?v=OSGv2VnC0go from 15 min 50 sec to 18 min 57 sec. On 20/07/2020 15:42, Guido van Rossum wrote:
Also, let me be clear that this feature will never be added to the language.
With respect, that seems pretty dogmatic, given that for...else is one of the most confusing features of Python. What would be so terrible about allowing, at minimum, `if not break:' as a synonym for 'else:'? Best wishes Rob Cliffe

On 21/07/2020 22:07, Barry wrote:
I'm sorry, of the above two points I don't understand 1. at all, and I only half understand 2. Please could you rephrase more clearly for an idiot like me.:-) But as to `if` after `for` being confusing, are you seriously saying that `else` after `for` is *less* confusing?

On Tue, Jul 21, 2020 at 10:07:47PM +0100, Barry wrote:
1. Because that not what else mean today. Its elif never looped.
py> for x in [1,2]: ... print("inside loop") ... else: ... print("elif never looped") ... inside loop inside loop elif never looped This is why I have long-argued that the keyword here should be *then* not else. The semantics are that the loop executes, *then* the following "else" block executes, unless we have transferred control elsewhere by jumping out of the loop with return, raise, or break. Mistaking the semantics for "if never looped" is a very common mistake. Welcome to the club :-) -- Steven

Hello, On Wed, 22 Jul 2020 09:45:31 +1000 Steven D'Aprano <steve@pearwood.info> wrote:
But no, loop executes, *or else* the following "else" block executes ;-). That's the logic of founding fathers. After one grasped that logic, one comes to appreciate a weird beauty of it. The verdict remains the same though: "Do Not Use".
[] -- Best regards, Paul mailto:pmiscml@gmail.com

On Wed, Jul 22, 2020 at 1:15 PM Paul Sokolovsky <pmiscml@gmail.com> wrote:
There's a buggy construct that I see VERY frequently in my students' code (which I'll show in Python syntax here, but this can happen in any language) that closely parallels the actual semantics of Python's for-else, and showcases its value. # Find the first two-digit number, or return 99 def find_big_number(pile): for number in pile: if number > 10: return number else: return 99 It's extremely common to see this "else" attached to its "if" in a way that prevents the loop from finishing. Now, obviously, in the case where you're using a "return" as the body of the else, you could just unindent it as unconditional post-loop code, but that doesn't work for other examples, and as a general rule, it seems that people like to think in terms of "if it is what we want, do this, otherwise do that". And that behaviour is exactly what a for-else loop does. ChrisA

On Wed, Jul 22, 2020 at 06:14:39AM +0300, Paul Sokolovsky wrote:
I am confused. I don't understand your comment. Your "But no" suggests to me that you are disagreeing with me. Your comment "loop executes *or else* ..." suggests that you are denying the evidence of the code, and defending the idea that either the loop runs, or the else clause runs, but not both. You literally say that the loop runs, *or else* (xor) the else block runs. But you say this in response to a demonstration that the loop runs, *and* the else block runs. So I am stuck in a "does not compute" moment. I cannot see any other interpretation of your comment apart from disagreement: "No Steven, you are mistaken, never mind that the code you copied and pasted demonstrates that the loop block and the else block *both* run, never mind that anyone can run their own tests to demonstrate that *both* run, that's wrong, either the loop runs *or else* the else block runs but not both." If there is another interpretion of your comment it is too subtle for me after a long and tiring day. I cannot see any interpretion other than you literally denying the reality of how for...else blocks work. And I cannot believe that you would do that. Surely I must be misinterpreting you. Hence, "Does Not Compute". What am I missing? -- Steven

Hello, On Wed, 22 Jul 2020 20:00:29 +1000 Steven D'Aprano <steve@pearwood.info> wrote: []
Nope, I'm not saying that. I'm saying that if loop can run, it runs. Else if it can't run (which happens when it's exhausted), then "else" runs. The only unclear thing here is that "break" skips it. That's not immediately obvious, but if you think about, it starts to make sense, because otherwise no "else:" would be needed at all. And I'm saying that not in justification of "else:", but as an example of learning how to understand what made the language author chose "else:" as the name of that clause. The above aren't my words either, that's what I read to grasp that stuff (and it stuck only when I peered thru enough bytecode). If there is any obvious conclusion to make from all that, that would be the same "Do Not Use" already mentioned. On the topic of "change something", I'd personally wouldn't find it a tragedy if: --- for ...: elif not break: --- was made a synonym of --- for ...: else: --- But I'm worried about the usual scope creep in the discussion here, with all the further "if break/if empty/if not empty" adhoc clauses. And I find "else: # if not break" to be pretty neat already, just need to crusade to make linters require it by default, as a second choice after unconditionally warn on using "else:" in the first place. Note that you'll need to make linter-crusade even if "elif not break:" is adopted, because "else:" stays put, for backward compatibility. -- Best regards, Paul mailto:pmiscml@gmail.com

Steven D'Aprano writes:
On Wed, Jul 22, 2020 at 06:14:39AM +0300, Paul Sokolovsky wrote:
But no, loop executes, *or else* the following "else" block executes ;-).
He means the loop *suite* executes (this includes "getting to" a break statement or other control flow that leaves the loop *statement* entirely), and if it doesn't, the else suite does. This is "why" such nonlocal exits differ from finally in that they don't run the else suite. I personally think this is a perfectly clear and convincing argument for "else" as the keyword for this statement (once "suite" is added to Paul's phrasing). This is why programmers should major in English, and do a graduate degree in programming if they really think they need a degree in programming.
You mean "the part of the loop *statement* that starts with 'for' or 'while'" runs, but this is somewhat inconsistent as the else suite is also part of the loop statement. I don't know of a concise but explicit way to express what you mean, although I understood it perfectly well.

On 23/07/2020 16:24, Stephen J. Turnbull wrote:
The upholders of the status quo regularly provide gallant explanations of why "else" is perfectly natural, even intuitive. The fact is, it isn't. If it were, it wouldn't **need** to be repeatedly explained by gurus to lesser mortals. I can't think of any other area of Python that needs to be defended so regularly and so vociferously, nor that very experienced Python programmers confess they find confusing. Swelp me, someone in this very thread (Barry) misunderstood it[1]. And suggesting that those of us who don't find it clear lack skill in English is just plain insulting. YMMV, but the only way I can grok it when I see it is to mentally translate "else" to "if no break". This is mental effort that would be spared or at least diminished if it were spelt in a more obvious way in the first place. Best wishes Rob Cliffe [1] or at least I think he did, I had trouble understanding him.

On Fri, 24 Jul 2020 at 02:18, Rob Cliffe via Python-ideas <python-ideas@python.org> wrote:
The upholders of the status quo regularly provide gallant explanations of why "else" is perfectly natural, even intuitive. The fact is, it isn't. If it were, it wouldn't *need* to be repeatedly explained by gurus to lesser mortals.
Fair point. It needs to be learned and remembered. It's not intuitive.
YMMV, but the only way I can grok it when I see it is to mentally translate "else" to "if no break". This is mental effort that would be spared or at least diminished if it were spelt in a more obvious way in the first place.
Again, probably true. With hindsight, if we were designing Python from scratch now, we'd probably not spell this as "else". We'd probably omit it altogether rather than using an alternative spelling, but that's a side issue. BUT - we're not designing Python now. The "else" clause on loops has been around for many years. It's in books, training courses and in existing, working code. We can't break all of that without a fairly large cost. And (as I've noted before) having *two* ways of writing this obscure construct would be even more confusing, particularly as people working with existing code or learning from existing training materials will naturally see the (presumably less intuitive and obvious) "else" spelling. So even accepting all of your points above, it's still very unlikely this will change. Not because there's no benefit, but because the cost is too high. Paul

On Thu, Jul 23, 2020, 9:19 PM Rob Cliffe via Python-ideas
I have used Python for 22 years, and I still cannot remember what else does in a loop for more than a few minutes at a time. It's easy to remember "it has something to do with whether there was a break." But neither direction in that choice yet feels obvious to me. I've read all the posts in this thread. I watched Raymond's explanation from a talk a few years ago. I've read Guido's explanation. I've read Knuth. I have a graduate degree in humanities and am a professional writer. I'm a native English speaker. It's still not intuitive to me. In my own code I just avoid the construct. I reckon I'm +1 on "some better spelling" ... although I manage fine without using it. I rarely see it in the wild, probably because it is confusing. I can't think of any other area of Python that needs to be defended so

To avoid the ambiguity of if after for why not follow for with elif? for x in ...: ... elif break: # break was called elif not break: # looped at least once and break not used elif pass: # same as else today # loop'ed no times (I always have to think what else means after a for). Barry

how about: for something in some_iterable: some_stuff_with_maybe_a_break else if not break: something_more No new keywords :-) or: for something in some_iterable: some_stuff_with_maybe_a_break else: # if not break: something_more and no changes needed to Python! I may actually start doing that myself ... As for the "loop didn't run at all" case: Does anyone find a need for that? Personally, I've found that everytime I do some kind of check for an empty iterable before a loop, it was totally unnecessary. A for loop means: "Do this stuff to all the items in this iterable." Most of the time, if there's nothing there, you don't need to do the stuff, and that's that. -CHB On Tue, Jul 21, 2020 at 5:28 PM Ethan Furman <ethan@stoneleaf.us> wrote:
-- Christopher Barker, PhD Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython

Hello, On Tue, 21 Jul 2020 17:48:35 -0700 Christopher Barker <pythonchb@gmail.com> wrote:
This is the most genius solution posted to this thread. And if the thread didn't die after van Rossum's post, I don't cheer hopes it would die now, but let me sprinkle in another "fresh" thought. First let me remind how this thread started:
ELSE-clause in FOR and WHILE has unclear syntax. I suggest new clause instead
Then various people started to throw in variants of even more unclear and confusing syntax (like "if" after "for"), with some percentage of those people demonstrating not understanding how the original "else" works. But consider following idea: if it's confusing, DO NOT USE it. You don't hear that often, but: treat Python as a generic programming language, not as a bag of tricks. The fact that most other languages don't have extra clause after "for" is enough of a reason to not use it in Python either. So why it exists at all then? It's there for people who don't find it confusing, for very responsible use. As a random example, after studying 2 (bytecode) Python compilers and having written my own (so I know what code is generated from for-else), I no longer find it confusing. I actually found 2 intuitive ways to use that construct, in the very compiler mentioned - after all, if you eyeball a Python compiler, you either know, or ready to learn, how all language constructs work. For anything else - clear ban. Everyone should consider that too. (But please leave the language syntax alone (backwards compatibility, etc.), at least that's a suggestion which comes out from van Rossum's post).
I find the need for that regularly. And I use the obvious syntax which everyone else uses: if not seq: print("This page is intentionally left blank") else: for i in seq: ... Any adhoc, confusing syntax someone may imagine to add, would go to the same "DO NOT USE" category. So, I pray to van Rossum's answer that something like that will never be added to the language. (Which is hard to hang hopes on, given all the mess added recently.) [] -- Best regards, Paul mailto:pmiscml@gmail.com

Not so easy for an iterator though. I’m more likely to do something like this: Page = NewPage() For content in iterable: Page.Add_stuff(content) If not Page: print("This page is intentionally left blank") (Sorry For the non PEP8 compliant capitalization— damn phone) -CHB
--
Christopher Barker, PhD Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython

On Wed, 22 Jul 2020 at 04:47, Paul Sokolovsky <pmiscml@gmail.com> wrote:
Frankly, saying that a part of a language that is frequently misunderstood, is *never* allowed to be improved is disappointing when the suggestion that it can be (somehow) has been so well received by everyone else.
Many people offering approaches is not muddling the thread. Clearly, most people here agree that `for...else` is confusing/unintuitive on it's own, and could be improved (not removed, but improved). The discussion was trying to find an improvement that people agree on as well. The reason there are so many offerings, is probably because everyone has had a similar thought about it in the past. -- Notice: This email is confidential and may contain copyright material of members of the Ocado Group. Opinions and views expressed in this message may not necessarily reflect the opinions and views of the members of the Ocado Group. If you are not the intended recipient, please notify us immediately and delete all copies of this message. Please note that it is your responsibility to scan this message for viruses. References to the "Ocado Group" are to Ocado Group plc (registered in England and Wales with number 7098618) and its subsidiary undertakings (as that expression is defined in the Companies Act 2006) from time to time. The registered office of Ocado Group plc is Buildings One & Two, Trident Place, Mosquito Way, Hatfield, Hertfordshire, AL10 9UL.

I'm (weakly) +1 for the concept of for..else being confusing, weird, and somehow not quite suitable/useful for many use-cases where it feels like it should. I'm -1 for each of the suggested improvements that I've understood so far. I agree that the suggested 'ban' on changes in this area is probably not helpful, however it feels like a sloppy way of saying that changes to the syntax are very unlikely to be practical, for a couple of annoying, but important reasons. The: for: ... else: # if not break: ... Solution seems to highlight this. The proposed convention of using comments here is clearly elective (nothing changes if you don't include the comment, although a style checker could require it, which would be a nice way of catching possible indentation errors) Because this is implemented as a comment, and thus optional, it feels pointless because the original confusion is still there for people who don't bother to add the comment, and less experienced coders are less likely to know about the convention. BUT it's probably as good as any other changes because... I don't feel that, on balance, the cost of making a breaking syntax change to the language (having worked on huge python codebases, the cost of any breaking syntax change is just massive) is justified here, so whatever improvements may be made would probably have to still support the old syntax as-is. The moment we retain the old syntax, then the new syntax becomes optional, and we're back in the problems with the comment approach. The only route I can see to a workable outcome here is to implement the: "else if not break:" clause as an optional alternate syntax, and update all the documentation to recommend using the new syntax over the old one (effectively silently deprecate for:...else:... syntax, but retain it indefinitely). But this has issues, because some people will still use the old syntax, so we'll end up with lots of code out there using both variants, and that's as likely to add to the general confusion here as reduce it. Steve On Wed, Jul 22, 2020 at 9:26 AM Mathew Elman <mathew.elman@ocado.com> wrote:

On Wed, 22 Jul 2020 at 10:54, Stestagg <stestagg@gmail.com> wrote:
I agree that for/while..else is not immediately obvious. But it's useful in some situations, and it *is* used in real-world code. I also agree that all of the proposals I've seen so far are at *least* as confusing, and would make the situation worse, not better. Generalising a bit, proposals that suggest *removing* else on loops are never going to get accepted, because they break existing code for no clear advantage. Ones that retain else on loops are bad because they end up providing two (typically equally confusing) ways of doing things. I don't think there's going to be any sort of "ban" on changing things, but I do think that it's reasonable to point out to people that all of this discussion is a waste of energy, and a distraction for people trying to follow this list for proposals that *do* have a chance of acceptance. The signal to noise ratio on this list can be bad at the best of times, and dropping ideas that simply won't work would help everyone. That's not to say that ideas that won't work aren't welcome - how will anyone learn what's feasible and what isn't if we shut down well-intentioned proposals? But proposers (and other participants) also need to accept that pushing an idea that isn't workable, is unproductive. Paul

On Wed, 22 Jul 2020 at 12:24, Paul Moore <p.f.moore@gmail.com> wrote:
agreed.
again, agreed.
I don't think this is the case. I agree that adding an alternative to `else` just to have an alternative is not a good fix, but adding explicit ways to refer to when breaking from the loop would make the use of `else` as it already is clearer. For example, breaking the change into 2 parts: 1. Adding `elif` to the `for...else` and `while...else` statements seems a logical extension. Guido has even said that the else in loops was invented by reasoning the connection of `if` to `while` (and then `while` to `for`). Perhaps this should be in its own discussion so as not to clutter this thread? 2. Adding a way to use this new `elif` to check the state of the loop. Possibly including if it was broken out of or if it was never entered. Such as having special local variables that are only defined in the block/frame of the loop.
I agree with you here too, 100%, but it does not feel like we have had said discussion. I would also make the suggestion that surely this thread, although noisey, is the right place to continue the discussion in case a consensus on an approach is reached. -- Notice: This email is confidential and may contain copyright material of members of the Ocado Group. Opinions and views expressed in this message may not necessarily reflect the opinions and views of the members of the Ocado Group. If you are not the intended recipient, please notify us immediately and delete all copies of this message. Please note that it is your responsibility to scan this message for viruses. References to the "Ocado Group" are to Ocado Group plc (registered in England and Wales with number 7098618) and its subsidiary undertakings (as that expression is defined in the Companies Act 2006) from time to time. The registered office of Ocado Group plc is Buildings One & Two, Trident Place, Mosquito Way, Hatfield, Hertfordshire, AL10 9UL.

On Wed, 22 Jul 2020 at 13:18, Mathew Elman <mathew.elman@ocado.com> wrote:
IMO, allowing for ... elif x == 2: do something to mean "if we didn't break out of the loop, and x is 2" would be really confusing. And to have the elif after a loop be limited to a different set of conditions than "ordinary" elif would *also* be really confusing.
2. Adding a way to use this new `elif` to check the state of the loop. Possibly including if it was broken out of or if it was never entered. Such as having special local variables that are only defined in the block/frame of the loop.
Same logic here - if we allow "elif not break" (for example), it would be really confusing to *arbitrarily* only allow that if the elif is attached to a loop. So we need to define what if x == 2: do something elif not break: what? means in general code. And that means inventing rules for the scope of "break as an expression". And in a similar vein, what does it mean to pass "break" to a function? def invert(flag): return not flag for ... elif invert(break): ... It's not that any of these things are *reasonable* to do, it's that all the special cases needed to disallow them would be confusing, and if we *didn't* disallow them, all of the rules needed to give them meaning in (conceded) unreasonable places would be confusing. The trick here is *not* to look at the case that you expect the construct to be used in - obviously it'll look good to you in that context, if you like the idea at all. What you need to look at is all the other ways it could be applied, and verify that the costs justify the improvement that you saw when you first encountered the idea. Paul

On Wed, 22 Jul 2020 at 13:45, Paul Moore <p.f.moore@gmail.com> wrote:
I don't think this would be any more confusing than `for...else` already is, and `while...elif...else` still seems like a logical extension of `while...else`. x=0 while x < 10: delta = get_delta(x) if delta == 0: break x += delta elif x%2: print(f"{x} is odd and > 10") else: print(f"{x} is even and > 10")
Absolutely! I would not suggest limiting it to any special cases. Hence why I split up the change. Adding a way to *also* use the elif to check the state of the loop is a separate discussion. Be that by using `break` as a special boolean or some other way.
means in general code. And that means inventing rules for the scope of
"break as an expression".
And in a similar vein, what does it mean to
That is fair enough, like I have said I am not attached (though others may be) to the idea of using `break` as a special boolean. Would it be more feasible to have a variable that persists beyond the scope of the loop and is not `break` but something else? For example, and this is not 100% serious but something like : `iter.broken`, `iter.enetered` etc.
Good point, I think this is a well made argument for *not* making `break` have a second meaning. -- Notice: This email is confidential and may contain copyright material of members of the Ocado Group. Opinions and views expressed in this message may not necessarily reflect the opinions and views of the members of the Ocado Group. If you are not the intended recipient, please notify us immediately and delete all copies of this message. Please note that it is your responsibility to scan this message for viruses. References to the "Ocado Group" are to Ocado Group plc (registered in England and Wales with number 7098618) and its subsidiary undertakings (as that expression is defined in the Companies Act 2006) from time to time. The registered office of Ocado Group plc is Buildings One & Two, Trident Place, Mosquito Way, Hatfield, Hertfordshire, AL10 9UL.

Hello, Why not just use Raymond's suggestion nobreak as a replacement of the else in loops and deprecate the else in Python 4? There is at least a precedent when not equal <> was deprecated in favor of != from Py2 to Py3. We could do the same with else/nobreak between Py3 and Py4. João Matos On 22/07/2020 14:36, Mathew Elman wrote:

On Thu, Jul 23, 2020 at 7:06 AM João Matos <jcrmatos@gmail.com> wrote:
Py2 supported both <> and !=, so code could be completely compatible with both branches just by using !=. You're proposing creating a new way of doing things and then deprecating or removing one of them, which either means there'll be two identical spellings, or you break everyone's code (or both). It's almost the opposite of the <> change. Please, everyone, can we NOT keep coming up with ideas that are basically "let's invent a new spelling for exactly the same thing, with no benefits, and demanding new keywords, so we can break people's code for no reason"? You can always just write your own transpiler to let yourself spell it your preferred way. ChrisA

On Thu, Jul 23, 2020 at 07:22:51AM +1000, Chris Angelico wrote:
Surely having a less confusing and misleading spelling is a benefit. We like to use Python because its syntax is so readable and obvious. "for...else" is a wart on the language, it is a lovely feature marred by a confusing keyword. The long term benefit is to reduce that confusion. We have heard from people in this thread that they reject for...else in code reviews because it is too confusing. The question to me is not "Why make this change for no benefit?" but "Is the benefit sufficient to go through the pain of change?". Guido seems to be open to the use of *soft keywords* now that CPython has moved to a PEG parser. Perhaps we could introduce a soft keyword as an alternative spelling for "else": for x in sequence: ... then: # allow the bike-shedding to begin :-( ... Being a soft keyword, outside of that context it will remain legal, so no-one needs to rename their "then" methods or variables. Code using "for...else" remains legal, although linters might warn against it. We need not actually depreciate the use of "else", not unless we plan to reintroduce it with a different meaning. But that's a separate discussion. So here's a concrete proposal: (1) `for...else` and `while...else` stay, for backwards compatibility. (2) Add a soft keyword "then" (bikeshed away...) to use in for and while loops, as an alternative preferred spelling to "else". (3) Update PEP 8 to make it clear that new code should use `for...then` and `while...then` rather than "else". (Old code need not change just for the sake of changing it.) (4) Linters and style-checkers can prefer `then`, but the interpreter itself will remain neutral and accept both. To avoid all doubt: (5) There is no plan to depreciate the hard keyword `else`, not even a PendingDepreciation warning. (6) Any suggestion that we repurpose `for...else` to mean "run this if the loop is empty" will have to justify itself. It is not part of this proposal. It seems to me that this is a pretty minor change, with little downside, that could have a big effect on the readability and usefulness of what's currently spelled as `for...else` and underused because people find it confusing. Compared to the benefits, the downsides are small: - Someone has to do the work. That's a one-off cost. - Double the tests: we have to verify `for...else` and `for...then` both work. This is a pretty small cost. - Two ways to do it. Despite the Zen, there are two ways to do many things in Python. But this is a pure alias: for...then and for...else are literally compiled to the same code. The Zen should be understood as *food for thought* not unbreakable rules of nature. If we accept this proposal, we could interpret it as follows: * the One Way to do it is `for...then`; * but for backwards compatibility there's also an alternative spelling that we prefer not to talk about, see the docs if you care. There are no runtime costs. The compiler should generate the exact same bytecode for the two spellings. There's no breaking backwards compatibility, as `then:` followed by a block is not currently legal. If `then` is a soft keyword, existing uses of "then" won't be affected.
How do I do that? That's not a rhetorical question. I keep wanting to study projects like LikePython for hints, because I am sick of *Old Man Python* telling me what I can and can't write, but somehow never find the time. https://jon.how/likepython/ If we had some sort of easy to use standard library support for transpiling code, then your advice could actually be practical and not just dismissive. "Pft, if you don't like it, write your own language" is not exactly practical for most people. Even if a transpiler is a tad simpler than writing an entire interpreter or compiler, it's still a new language. -- Steven

On Sat, Jul 25, 2020 at 11:13 AM Steven D'Aprano <steve@pearwood.info> wrote:
Minor, given that the existing spelling still has to be supported. Now you have two ways to do it, for the foreseeable future, and only style guides will differentiate. And a lot of style guides will say "prefer else because it's compatible with more Python versions". How long will it be before you can actually take advantage of it?
I don't dispute that, but that's very long term benefit, with a lot of short and medium term costs. The concept is a bit unusual (I don't know many other languages that support this with *any* spelling), so it still has to be explained, and a lot of people will still be confused no matter how you spell it. How much benefit do you actually gain?
That's a notable reduction in cost (and an improvement in flexibility for the bikeshedding - although that will, of course, mean that the bikeshedding takes ten times longer!), but the cost of creating a second way to do things isn't just the creation of the keyword.
Linters and style checkers will have to choose whether to recommend the "better" spelling (unquantifiable benefit) or the one that runs on more versions of Python (concrete, meaningful benefit).
I hope nobody EVER proposes that. Having code that means different things on different Python versions would be an absolute pest to work with. But if all the prior objections are overcome and "for... then" gains currency, there'd be some reasonable grounds for proposing a completely different keyword to have the "if loop is empty" semantics.
And all your documentation, examples, etc, have to care.
It depends how smart you want it to be. If you literally just search and replace "then:" into "else:" without caring about context, it'd be trivially easy. Obviously that's pretty risky, but adding a check for string literals would probably cover most normal code. Actually doing the job properly...
... would be best done with stdlib support, yes. I think import hooks can do everything that's needed, but I've never actually done it. Normally I'd just use a simple source-to-source transformation before execution, and usually I do things that aren't ever going to show up (string literals aside), so I don't need it to be very smart. ChrisA

On Fri, Jul 24, 2020 at 10:43 PM Chris Angelico <rosuav@gmail.com> wrote: SNIP
Already done (with a different keyword): https://aroberge.github.io/ideas/docs/html/nobreak.html André Roberge

On Sat, Jul 25, 2020 at 12:09 PM André Roberge <andre.roberge@gmail.com> wrote:
Thank you. Especially since the source code is extremely short: https://github.com/aroberge/ideas/blob/master/ideas/examples/nobreak.py I'd like to see this 'ideas' module (or similar) better known. It'd help a lot with complaints like Steven's. ChrisA

On Sat, Jul 25, 2020 at 12:49:36PM +1000, Chris Angelico wrote:
On Sat, Jul 25, 2020 at 12:09 PM André Roberge <andre.roberge@gmail.com> wrote:
Already done (with a different keyword):
That's a very nice project André, and I think it will probably useful for playing around with experimental new syntax. [Chris]
Before telling people to use the ideas module, perhaps you ought to read the IAQs: https://aroberge.github.io/ideas/docs/html/#infrequently-asked-questions-and... These sorts of hacks may be great for experimentation, but if people are so conservative that they reject an actual language feature, `for...else`, in code reviews, do you really think they're going to use `ideas` in production? I fear that even if we could get the average developer to say "I know, let's use `ideas` to write a DSL", the project manager -- and the rest of the team -- will probably respond "Over my dead body". We're a long, long way from this sort of thing being considered acceptable in production code. -- Steven

Hello, On Sat, 25 Jul 2020 18:44:55 +1000 Steven D'Aprano <steve@pearwood.info> wrote: []
You seem to mix up Python with some other language, perhaps Java. Its usecase dictate being used with "project managers" attached. I myself and I'm sure many other people use Python in settings which don't involve external project managers. Actually, we use Python exactly because it's possible to make useful projects using it without involvement of dedicated project managers, because Python is expressive and high-level language. And if expressiveness can be improved using custom syntax macros, etc., we'd like to be able to do it. If your recent idea, the "then:" keyword is based on "project managers" usecase, then... well, please disclose that fact. I personally don't appreciate adding confusing duplicate features to the core language to make "project managers" happy. But then again, in any professional, commercial setting any adhoc-semantics keyword for loops would be disallowed in the first place, no matter how it's called. That's because any Python project may be tomorrow rewritten in Java, day after in Go, etc. And as none of these languages (or most of others) have any such adhoc semantics for loops, neither it should be used in Python.
-- Steven
-- Best regards, Paul mailto:pmiscml@gmail.com

On Sat, Jul 25, 2020 at 11:40:06AM +1000, Chris Angelico wrote:
And a lot of style guides will say "prefer else because it's compatible with more Python versions".
Like they did in Python 2 when we had two ways of getting the next element from an iterator? # Python 2.7 py> it = iter([1, 2]) py> next(it) 1 py> it.next() 2 How many style guides said "Prefer the next *method*, because more Python versions (Python 2.2 on up) support it"? If there were any at all, they were a microscopic proportion of the ones that used the preferred next *function*, because that's what the std lib and documentation said to use. If the docs and PEP 8 says the soft-keyword "then" is preferred, the number of people who will stick to the "else" keyword a single day longer than they need to for backwards compatibility will rapidly drop to zero.
How long will it be before you can actually take advantage of it?
Of course libraries that need to support older versions of the language will have to use the old form, but that applies to *every* new feature. How many libraries that support Python 3.3 or 3.5 are using the walrus operator? Zero. Therefore we shouldn't have added the walrus operator, right? As the author of the walrus PEP, I'm sure you recognise that this sort of argument is weak. When we add new syntactic features we're looking forward to the future. Not everyone can be an early adopter using the cutting edge version with the latest features, but on the other hand most people aren't stuck forever supporting Python 3.3 (or 1.5) either. Some people will be able to use it the moment the feature is checked into the source repo. Some people won't be able to use it until 2040. And the majority will start to use it within a year or two. Like any other new language feature. [...]
And all your documentation, examples, etc, have to care.
Of course there will be a transition period where people say "I tried to run for...then and got a syntax error", but that doesn't last forever. When is the last time you've seen someone asking about syntax errors from `with` statements? Or async and await, for a more recent addition to the language? Look at PEP 530: https://www.python.org/dev/peps/pep-0530/ This PEP added a second way to do it: # Old Way, necessary before 3.6 result = [] async for i in aiter(): if i % 2: result.append(i) # New Way, only valid from 3.6 onwards result = [i async for i in aiter() if i % 2] If I were to go to StackOverflow, or Python-List, and ask "How do I run a list comprehension asyncronously?" how many people would give the Old Way? Would you? Of course the official docs have to document that "for...else" is accepted by the compiler and translated into "for...then", for backwards compatibility; and old documentation won't change. But new documentation would rapidly change to preferring the new version and not even mentioning the old version except maybe as a curio of the language. Who remembers using the Decorate-Sort-Undecorate idiom in Python? It was *everywhere*. Then we got a key function parameter, and seemingly overnight the DSU idiom just disappeared. -- Steven

On Sat, Jul 25, 2020 at 7:18 PM Steven D'Aprano <steve@pearwood.info> wrote:
I've no idea. When did the next() function come in, and what was it like while older versions than it were still current? Looking *now* isn't indicative.
Of course, but it IS an argument. The walrus operator gives new expressiveness. Async/await has a massive advantage over manually doing your wait points. The "but you can't use it yet" argument is a lot weaker than "it makes your code way cleaner", but the argument in favour of the current proposal is "it's a better choice of words". I don't dispute that it would be an improvement. I just dispute that it's enough of an improvement to create a new spelling for something that has no other advantage. Do you REALLY think that everyone will automatically understand it just because it's spelled "for... then" instead of "for... else"? ChrisA

On 7/25/2020 7:28 AM, Chris Angelico wrote:
Do you REALLY think that everyone will automatically understand it just because it's spelled "for... then" instead of "for... else"?
I wouldn't find "for ... then" any less confusing than "for ... else". I do find "for ... else if not break" easier to understand, but I'm not convinced its worth the hassle over "for ... else # if not break". Four keywords in a row! But all of these always make me wonder about a return inside the suite. Does the "else" part execute (answer: no). So as a rule, I avoid the construct entirely, not that it comes up very often, anyway. Eric

On Sat, Jul 25, 2020 at 4:39 AM Eric V. Smith <eric@trueblade.com> wrote:
I'm pretty sure that the OP on this proposed "then" as a placeholder, with the final choice of word to be determined. But I do think this is pretty darn illustrative --'cause I would find "then" even LESS intuitive, and it's a whole new keyword to boot! I'm one of those folks that have been around Python for a long time -- starting with 1.5 -- and I still find for-else a bit confusing, but I remember that it exists, so go figure it out when I need it. And that is not very often. Frankly, it's a nifty feature, but it's still not a very common use case -- so It's just not a very clear win to spell it better. And as the "then" example shows, it's really hard to find a better spelling -- it's just not that common a construct in programming languages, and it's not used that often in Python -- if it were, I"d probably remember what it meant :-)
well, there are two sides to usability: 1) Remembering it's there, and how to use it when you are writing code, which I think is not such a big deal -- if you remember its there, you can figure out how to use it. And if you don't remember it's there, then a better spelling isn't going to help. 2) understanding what it means when you are reading code -- and that, a better spelling would help with. But I don't get folks that would reject it in a code review -- I'd just suggest that you add a # if not break comment -- or better yet a comment that describes why it's there in the context of that problem -- as comments are supposed to do. Would you really as someone to replace: for dodad in all_the_things: if dodad == something_special: found_special_dodad = True break do_things_with(dodad) else: # the special one wasn't there -- need to process the stuff process(stuff) with this?: found_special_dodad = False for dodad in all_the_things: if dodad == something_special: found_special_dodad = True break do_things_with(dodad) ... if not found_special_dodad: # the special one wasn't there -- need to process the stuff process(stuff) The for--else construct exists for a reason: it's much cleaner than creating a flag and checking it later. Sure it would be nicer if it had a better spelling, but else # not break is pretty easy if you want to make your code more readable and there isn't need for an explanatory comment otherwise. I'm not advocating for any change (Obviously :-) ) -- but if there were to be one, I"d strongly vote for some version of else not break or else if not break because it introduces no keywords, and it's a lot more compatible documentation-wise than a different word -- it's almost like a built-in commnet :-) By that I mean that folks that see the two different spellings in two different tutorials or SO answers ,or whatever, are more likely to realize that they mean the same thing. But all of these always make me wonder about a return inside the suite.
Does the "else" part execute (answer: no). So as a rule, I avoid the construct entirely,
really? does an if-else clause execute if there's a return in the if? no. why would this be any more confusing?
not that it comes up very often, anyway.
This is the really key point. I wanted to use a real code example above, but I could not remember when I'd ever used it -- and it's hard to search for, so I couldn't find one. So: churn to make something rarely needed a little bit better -- I don't see the point. -CHB -- Christopher Barker, PhD Python Language Consulting - Teaching - Scientific Software Development - Desktop GUI and Web Development - wxPython, numpy, scipy, Cython

On Sat, Jul 25, 2020, 3:12 PM Christopher Barker
As bikesheds go, I like a "soft keyword" which PEG apparently makes easier. Maybe 'nobreak' or 'notbreak' or 'finished'. But as Christopher notes, the spelling 'else: # not break' is fine for readability, even if not for remembering it.

On 7/25/2020 3:11 PM, Christopher Barker wrote:
Because I always remember "for ... else" has something to do with leaving the loop early, but I don't recall if it's more like try ... finally, or if it's related to the loop exiting early, or the loop not exiting early, or something else I can't recall. So, the answer to your "really?" question is "yes". Eric

How about we just document the whole feature as deprecated and never speak of it again? -- Greg

Mathew Elman writes:
The highly improbable is frequently well-received. What can surely be improved is the documentation, specifically the Tutorial. Something like The else clause of a loop statement has frequently been misunderstood. In a for or while loop *statement*, on each iteration, the condition is tested and exactly one of the following occurs: 1. If truthy, the loop *suite* runs to completion and the test is repeated for the next iteration, 2. OR the loop *suite* runs and there is a nonlocal exit such as return or break or raise, which exits the statement as well. 3. OTHERWISE the condition is false, and the else suite, if any, runs, then the statement is exited. The emphasis is for contrast in this discussion. The Language Reference already says precisely this, although much more concisely. I don't expect supporters of "elif not break" etc to think this is sufficient, and supporters of the Else Ban similarly. Please consider if this is helps clarify the Tutorial, and if it doesn't get booed into oblivion, I'll work up a patch (I think that the section on control flow would benefit from some reorganization as well, "just stick it in somewhere" is not what I have in mind :-). Steve

On Thu, 23 Jul 2020 at 16:25, Stephen J. Turnbull < turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:
Credit where credit is due, I think this is definitely an improvement. It does make it require slightly less meticulous reading to understand `else`. However, I still think that there is value in improving the `for...else` and `while...else` intuitiveness, if it can be done at an acceptable cost. (As is the case with any change) IMO the solution is not to change `else` but to add an additional with the opposite meaning that makes the use of `else` with `for` and `while` more intuitive, such as adding `elif`, which feels natural, and a special boolean, which perhaps doesn't. Or adding `except` for catching raised Exceptions rather than breaks, which makes `else` clearly behave how it does for `try`. Or another solution that achieves the additional clarity *without* removing/changing else itself.
Steve
-- Notice: This email is confidential and may contain copyright material of members of the Ocado Group. Opinions and views expressed in this message may not necessarily reflect the opinions and views of the members of the Ocado Group. If you are not the intended recipient, please notify us immediately and delete all copies of this message. Please note that it is your responsibility to scan this message for viruses. References to the "Ocado Group" are to Ocado Group plc (registered in England and Wales with number 7098618) and its subsidiary undertakings (as that expression is defined in the Companies Act 2006) from time to time. The registered office of Ocado Group plc is Buildings One & Two, Trident Place, Mosquito Way, Hatfield, Hertfordshire, AL10 9UL.

On Tue, Jul 21, 2020 at 05:48:35PM -0700, Christopher Barker wrote:
I always do that, not because I need it now, but because the next person who reads my code in six months might need it. That person might even be me.
If we had it, I would use it. It is generally possible to work around the lack, e.g. with an explicit test of a sequence (but that doesn't work with iterators), but I find that sometimes it isn't *obvious* that the empty loop case is handled correctly: for x in iterable: do stuff continue processing If iterable is empty, is the code still correct? Sometimes that's obvious, but when it *isn't* obvious I wish there was a way to run this: for x in iterable: do stuff if loop was empty: whatever is needed to make it obviously correct such as an assert, or early return I'd rather have an extra couple of lines of code and obviously correct code than save a few lines and have to think hard about whether the code is correct :-) More rarely I do need to treat the empty case specially. If the iterator is a sequence I can test the length up front, but this doesn't work with iterables. It's not *hard* to work around this, it's just inelegant. -- Steven

On 20/07/2020 09:56, Alex Hall wrote:
But detecting the number of iterations (however it's spelt) might be tricky. Always counting the number of iterations would slow down *every* for/while loop - surely unacceptable. So the compilation process must only incorporate this loop-counting when the loop is followed (after 100 lines of code??) by a reference to the loop count. Another way would be for the first iteration (i.e. the first call of `next') to be coded separately (in the bytecode). If the first call does not raise StopIteration, it could set a flag meaning "at least 1 iteration occurred", But this would bloat the code, and again doesn't seem like a great idea if it applies to *every* for/while loop. Therefore: I suggest that the proposal should be modified to just detect break or no break. That's already progress. And if in future someone thinks of a brilliant way of detecting zero (or N) iterations, that can be added later.

I don't know what to do about the zero iterations case, though. Perhaps simply `if not:' Best wishes Rob Cliffe

On Wed, Jul 15, 2020 at 05:45:05AM +0000, Steve Barnes wrote:
Sorry Steve, "finally" would be a terrible name because it behaves nothing like try...finally. In try blocks, the finally block is *always* executed, even if you raise, even if you return. (To be precise, there are odd and unusual cases where finally won't be executed, such as if the interpreter process is `kill -9`'ed, or if a power surge fries the CPU. But under normal processing, finally always runs.) But the for...finally (renamed from for...else) is not like that. If anything, it's the opposite of finally: it is a block designed to be skipped, not a block designed to always run. Any of `break`, `return` or `raise` will cause the for...finally clause to be skipped. So we would be swapping one form of confusion to another ("why is my finally clause not executed?"). -- Steven

Thank to all disputants. It is possible to borrow the keyword "case" from PEP-622 (when it appears https://www.python.org/dev/peps/pep-0622). Keyword "case" can be written instead of "else/elif". I.e. case COND: ... [case COND: ...] [case COND: ...] All conditions COND must be different. Last "case COND:" can be replaced with "else:".

On Sun, 19 Jul 2020 at 15:43, Олег Комлев <ar12wtz@gmail.com> wrote:
For me this is -1 because "for... case" and "while... case" don't read like english. I also think the issue is less what keyword is used from "case", "if", "except" or "joojoo" rather what the "COND" look like. Obviously this depends on what the keyword is e.g. for "case"/"if" they should be predicates, for "except" they should be exceptions and if adding a new keyword it may be they are not needed. But I would say deciding on those is the priority. Side Note: It does feel like "elif" should be part of the "for-else" and "while-else" (especially while) compound statements. -- Notice: This email is confidential and may contain copyright material of members of the Ocado Group. Opinions and views expressed in this message may not necessarily reflect the opinions and views of the members of the Ocado Group. If you are not the intended recipient, please notify us immediately and delete all copies of this message. Please note that it is your responsibility to scan this message for viruses. References to the "Ocado Group" are to Ocado Group plc (registered in England and Wales with number 7098618) and its subsidiary undertakings (as that expression is defined in the Companies Act 2006) from time to time. The registered office of Ocado Group plc is Buildings One & Two, Trident Place, Mosquito Way, Hatfield, Hertfordshire, AL10 9UL.
participants (25)
-
Alex Hall
-
André Roberge
-
Barry
-
Barry Scott
-
Chris Angelico
-
Christopher Barker
-
David Mertz
-
Dominik Vilsmeier
-
Eric V. Smith
-
Ethan Furman
-
Greg Ewing
-
Guido van Rossum
-
Jonathan Fine
-
João Matos
-
Mathew Elman
-
MRAB
-
Paul Moore
-
Paul Sokolovsky
-
Random832
-
Rob Cliffe
-
Stephen J. Turnbull
-
Stestagg
-
Steve Barnes
-
Steven D'Aprano
-
Олег Комлев