Idea: Extend "for ... else ..." to allow "for ... if break ..." else
There's been a discussion of the "for ... else ..." construction in Python. Here's a suggestion as to how we might improve matters, and perhaps usefully extend the language. I hope it might benefit some, without harming anyone else. Aside: I've not read the whole of the previous discussion, and it may be that some or all of what I say has already been expressed there. So apologies for any missing credits to others. The errors, I'm responsible for. Here's what happens at present. for i in items: LOOP_BODY else: print('exit via StopIteration') I find the following clearer (where 'if break' is a new language 'compound keyword'). for i in items: LOOP_BODY if break: pass else: print('exit via StopIteration') This would now allow us to write for i in items: LOOP_BODY if break: print('exit via break') else: print('exit via StopIteration') Sometimes a loop has multiple break commands, which have different purposes. So a further extension might be for i in items: LOOP_BODY if break left: print('exit via break left') elif break right: print('exit via break right') elif break: print('exit via some other break') else: print('exit via StopIteration') To allow this to work, we extend the language to allow commands such as break left break right as well as the usual break Here the identifiers 'left' and 'right' look like variable names, but in fact they are labels. The compiler can, and I think should, produce a hard-coded jump from command break right to the code block under elif break right: This is the basic idea, keeping the syntax close to Python as it now is (but of course adding to the semantics). Some programmers, and I think I'm one, might want a clearer distinction between for i in items: LOOP_BODY if break: do_something and for i in items: LOOP_BODY if broke: do_something For this reason I tentatively suggest instead for i in items: LOOP_BODY case: break left: print('exit via break left') break right: print('exit via break right') break: print('exit via some other break') else: print('exit via StopIteration') Some people have asked a built-in means to detect, at the end of the iteration, whether theitems was empty to begin with. The syntax could easily provide this, for example via case: zero: print('no items to process') However, if we adopt this perhaps we'd also like to retain the simpler for ... if break ... else ... construct. I hope this helps. -- Jonathan
Jonathan Fine writes:
Sometimes a loop has multiple break commands, which have different purposes. So a further extension might be for i in items: LOOP_BODY if break left:
An if here is already valid syntax. I'm pretty sure that the parsers can handle it. But Python statement-introducing keywords are intentionally quite distinct for human consumption. The fact that else and elif are similar in some ways is mitigated by the fact that they have very similar semantics. It's also true that the "in" and "is" operators would be somewhat confusable, but I don't think that's as important as having quite distinct statement keywords.
print('exit via break left') elif break right: print('exit via break right') elif break:
'break' is of course already a "hard" keyword, globally reserved. But this looks very much like elif flag: to me.
print('exit via some other break') else: print('exit via StopIteration')
Finally, much of what this syntax allows is possible like this: for i in items: LOOP_BODY_ABOVE_BREAKS if LEFT: # NOTE: additional indentation here is hidden in LOOP_BODY # in the OP. print('exit via break left') break; LOOP_BODY_AMID_BREAKS if RIGHT: print('exit via break right') break; LOOP_BODY_AMID_BREAKS if CENTER: print('exit via some other break') break; LOOP_BODY_BELOW_BREAKS else: print('exit via StopIteration') So the new feature is to distinguish some breaks from other breaks and collect the action suites for breaks that have exactly the same actions in a single place. But how often is this going to be useful? If it *is* useful, it occurs to me that (1) this looks a lot like the try ... except ... pattern, and (2) breaks are generally perceived as exceptional exits from a loop. Instead of "if break [LABEL]", "except [LABEL]" might work, although the semantic difference between labels and exceptions might get a ton of pushback. That said, I can't think of a time where I wanted more than one kind of a break from a loop, let alone where some kinds existed in multiple instances. So I'm -1 unless we see plausible use cases for the extra power, and a before-after comparison shows a perceptible readability improvement. Steve
.
If it *is* useful, it occurs to me that (1) this looks a lot like the try ... except ... pattern, and (2) breaks are generally perceived as exceptional exits from a loop. Instead of "if break [LABEL]", "except [LABEL]" might work, although the semantic difference between labels and exceptions might get a ton of pushback.
...
Steve
In the related thread I suggested using `except`, but it was largely ignored. *If* you want tou propose clearer syntax for this, please extend the loop
syntax, not the ‘if’ syntax. So, ‘case ... zero’ makes more sense than ‘if [not] break’.
—Guido
So I understand, does this mean that any extended syntax for this should be *totally* new and not draw on existing constructs such as `try-except` or `if-else`? Or just that the additional clarity should come from extending the loop rather than the implicit `if`? Mathew -- 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.
Thank you all, particularly Guido, for your contributions. Having some examples will help support the exploration of this idea. Here's a baby example - searching in a nested loop. Suppose we're looking for the word 'apple' in a collection of books. Once we've found it, we stop. for book in books: for page in book: if 'apple' in page: break if break: break However, suppose we say that we only look at the first 5000 or so words in each book. (We suppose a page is a list of words.) This leads to the following code. for book in books: word_count = 0 for page in book: word_count += len(page) if word in page: break if word_count >= 5000: break found if break found: break At this time, I'd like us to focus on examples of existing code, and semantics that might be helpful. I think once we have this, the discussion of syntax will be easier. By the way, the word_count example is as I typed it, but it has a typo. Did you spot it when you read it? (I only noticed it when re-reading my message.) Finally, thank you for your contributions. More examples please. -- Jonathan
On 29.07.20 13:33, Jonathan Fine wrote:
Thank you all, particularly Guido, for your contributions. Having some examples will help support the exploration of this idea.
Here's a baby example - searching in a nested loop. Suppose we're looking for the word 'apple' in a collection of books. Once we've found it, we stop.
for book in books: for page in book: if 'apple' in page: break if break: break
This can be realized already with `else: continue`: for book in books: for page in book: if 'apple' in page: break else: continue break However it looks more like this should be a function and just return when there is a match: for book in books: for page in book: if 'apple' in page: return True Or flatten the loop with itertools: for page in it.chain.from_iterable(books): if 'apple' in page: break This can also be combined with functions `any` or `next` to check if there's a match or to get the actual page.
However, suppose we say that we only look at the first 5000 or so words in each book. (We suppose a page is a list of words.)
This leads to the following code.
for book in books: word_count = 0 for page in book: word_count += len(page) if word in page: break if word_count >= 5000: break found if break found: break
This also could be a function that just returns on a match. Or you could use `itertools.islice` to limit the number of words. I don't see a reason for double break here.
At this time, I'd like us to focus on examples of existing code, and semantics that might be helpful. I think once we have this, the discussion of syntax will be easier.
By the way, the word_count example is as I typed it, but it has a typo. Did you spot it when you read it? (I only noticed it when re-reading my message.)
Finally, thank you for your contributions. More examples please.
I think the need for two (or more) distinct `break` reasons or the same `break` reason at multiple different locations in a loop is pretty rare. Are there any counter examples? Otherwise such cases can be handled already today and there's no need for additional syntax (apart from the "else" ambiguity).
Jonathan Fine writes:
Here's a baby example - searching in a nested loop. Suppose we're looking for the word 'apple' in a collection of books. Once we've found it, we stop.
While I was writing a reply, several people replied with very similar comments, so I won't repeat them. But these two examples are so obnoxious I had to post them:
for page in (page for book in books for page in book if 'a' in page): ... break ... page 'abc' [page for book in books for page in book if 'a' in page][0] 'abc'
I note that both of these examples could be handled by having a way to break out of 2 loops at a time. Rob On 29/07/2020 12:33, Jonathan Fine wrote:
Thank you all, particularly Guido, for your contributions. Having some examples will help support the exploration of this idea.
Here's a baby example - searching in a nested loop. Suppose we're looking for the word 'apple' in a collection of books. Once we've found it, we stop.
for book in books: for page in book: if 'apple' in page: break if break: break
However, suppose we say that we only look at the first 5000 or so words in each book. (We suppose a page is a list of words.)
This leads to the following code.
for book in books: word_count = 0 for page in book: word_count += len(page) if word in page: break if word_count >= 5000: break found if break found: break
At this time, I'd like us to focus on examples of existing code, and semantics that might be helpful. I think once we have this, the discussion of syntax will be easier.
By the way, the word_count example is as I typed it, but it has a typo. Did you spot it when you read it? (I only noticed it when re-reading my message.)
Finally, thank you for your contributions. More examples please.
-- Jonathan
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/ECALTX... Code of Conduct: http://python.org/psf/codeofconduct/
Being able to break multiple loops and having "labelled" breaks would be achievable using `except`, i.e. adding `except` to the loop statements before `else` like this: for elem in iterable:
... if should_break(elem): raise SomeException except SomeException as e: handle_break_behaviour(e) else: print("Did not break")
would be sugar for: try:
for elem in iterable: ... if should_break(elem): raise SomeException except SomeException as e: handle_break_behaviour(e) else: print("Did not break")
I (and others) have suggested this before and no one has said it's a *bad *option, it's just been ignored, despite seeming to be an intuitive way to accomplish `else` clarity, "labelled" breaks and breaking from multiple loops. Is there a reason that this suggestion is worse / no better than adding special break syntax? As for an example for labelled breaks how about something of the form: def insert_ordered_no_duplicates(duplicate_free_list, item):
for i, elem in enumerate(duplicate_free_list): if elem == item: break already_present if elem > item: break location_found case already_present: return duplicate_free_list case location_found: new_list = duplicate_free_list[:] new_list.insert(i, item) return new_list new_list = duplicate_free_list[:] new_list.append(item) return new_list
which you can conceivably have a nested case where you don't want to let duplicate inserts even be attempted like this: def insert_many_ordered_strictly_no_duplicates(dup_free_list, items):
new_list = dup_free_list[:] for item in items: for i, elem in new_list: if elem == item: break already_present if elem > item: break location_found case already_present: break duplicates_attempted case location_found: new_list.insert(i, item) else: new_list.append(item) case duplicates_attempted: return dup_free_list[:] return new_list
On Wed, 5 Aug 2020 at 13:40, Rob Cliffe via Python-ideas < python-ideas@python.org> wrote:
I note that both of these examples could be handled by having a way to break out of 2 loops at a time. Rob
On 29/07/2020 12:33, Jonathan Fine wrote:
Thank you all, particularly Guido, for your contributions. Having some examples will help support the exploration of this idea.
Here's a baby example - searching in a nested loop. Suppose we're looking for the word 'apple' in a collection of books. Once we've found it, we stop.
for book in books: for page in book: if 'apple' in page: break if break: break
However, suppose we say that we only look at the first 5000 or so words in each book. (We suppose a page is a list of words.)
This leads to the following code.
for book in books: word_count = 0 for page in book: word_count += len(page) if word in page: break if word_count >= 5000: break found if break found: break
At this time, I'd like us to focus on examples of existing code, and semantics that might be helpful. I think once we have this, the discussion of syntax will be easier.
By the way, the word_count example is as I typed it, but it has a typo. Did you spot it when you read it? (I only noticed it when re-reading my message.)
Finally, thank you for your contributions. More examples please.
-- Jonathan
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.orghttps://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/ECALTX... Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/YV4V2F... Code of Conduct: http://python.org/psf/codeofconduct/
-- 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 05/08/2020 15:29, Mathew Elman wrote:
Being able to break multiple loops and having "labelled" breaks would be achievable using `except`, i.e. adding `except` to the loop statements before `else` like this:
for elem in iterable: ... if should_break(elem): raise SomeException except SomeException as e: handle_break_behaviour(e) else: print("Did not break")
would be sugar for:
try: for elem in iterable: ... if should_break(elem): raise SomeException except SomeException as e: handle_break_behaviour(e) else: print("Did not break")
I (and others) have suggested this before and no one has said it's a /bad /option, it's just been ignored, despite seeming to be an intuitive way to accomplish `else` clarity, "labelled" breaks and breaking from multiple loops. Is there a reason that this suggestion is worse / no better than adding special break syntax?
It's certainly a reasonable option. Indeed, I would consider using the second (currently legal) version in my own code if it seemed appropriate. Some pros and cons that occur to me (I may be biased, YMMV): Pros: (1) It can cleanly separate the handling of break-type exceptions and other exceptions, if needed. (2) It actually clarifies what the dreaded "else" means! (3) it allows you to group your "break" cases using exception subclasses (although this is probably OTT for most use cases). Cons: (4) It's more work. You have to decide what exceptions to use and (most likely) create them. (5) It adds the runtime overhead of setting up the "try" and possibly raising the exception. (6) Putting (implicitly) try...except around a possibly long for-suite feels bad somehow, even though it wouldn't catch other unwanted exceptions. (7) It does not catch the "zero iterations" case. If, contra your suggestion, special syntax were to be added, it could use "except" instead of "if ... elif". For example (this is just doodling, it's not a fully thought-out proposal): for x in range(10): ... if <something happens>: break "oops" # under the hood this is a compiled jump, not the raising of an exception if <something else happens>: break 42 except "oops": <handle something> except 42: <handle something else> except break: # catches all "break"s not already explicitly caught pass else: print("Did not break") Rob Cliffe
Mathew Elman writes:
Being able to break multiple loops and having "labelled" breaks would be achievable using `except`, i.e. adding `except` to the loop statements before `else` like this:
This would certainly be consistent with the existing use of the except keyword, unlike the proposal to have it take both exceptions (in 'try' statements) and break labels (in 'for' and 'while' statements). However, we would probably not want to burden all loops with the exception-handling machinery, so the compiler would have to do some hacky backtracking (I doubt that the arbitrary lookahead needed to handle "maybe we got some except clauses coming?" during parsing would be acceptable) and fill that in *after* recognizing that there are except clauses in this for statement. Second, generally Python tries to avoid overloading keywords with multiple semantics. The potential for confusion and misunderstanding of "except" (which I've suggested myself and now dislike) is pretty large I think. It might be possible to save that level of indentation with this syntax: try for elem in iterable: ... if should_break(elem): raise SomeException except SomeException as e: handle_break_behaviour(e) else: print("Did not break") (and I suppose you could do the same for any control flow statement, although I'm not sure offhand that the various keywords are 100% disjoint -- that would need to be checked). But I don't think it's worth it. I don't see enough benefits from this mixing of try and for to make it worth the complexity.
I (and others) have suggested this before and no one has said it's a *bad *option,
It is, though, for the reasons above as well as the reasons Rob gives in his parallel followup. Steve
Thank you both for the feedback. Some pros and cons that occur to me (I may be biased, YMMV):
Pros: (1) It can cleanly separate the handling of break-type exceptions and other exceptions, if needed. (2) It actually clarifies what the dreaded "else" means! (3) it allows you to group your "break" cases using exception subclasses (although this is probably OTT for most use cases). Cons: (4) It's more work. You have to decide what exceptions to use and (most likely) create them.
(5) It adds the runtime overhead of setting up the "try" and possibly
raising the exception. (6) Putting (implicitly) try...except around a possibly long for-suite feels bad somehow, even though it wouldn't catch other unwanted exceptions. (7) It does not catch the "zero iterations" case.
It is possible that 4 and 7 may be fixed by adding 2 new Exception subclasses, e.g. `BreakException`, which would "replace" break although using break would still be possible, and `NoIterationException` (though this may not be the cleanest approach). The question then becomes what to do with these when there is no `except`. At the sacrifice of automatically breaking out of multiple loops, they could be silently ignored unless caught explicitly? I do not know well enough how the python interpreter sets up `try-except` blocks to realistically respond to 5 and 6 but I can indeed see these being sticking points. On Thu, 6 Aug 2020 at 08:57, Stephen J. Turnbull < turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:
Mathew Elman writes:
Being able to break multiple loops and having "labelled" breaks would be achievable using `except`, i.e. adding `except` to the loop statements before `else` like this:
This would certainly be consistent with the existing use of the except keyword, unlike the proposal to have it take both exceptions (in 'try' statements) and break labels (in 'for' and 'while' statements).
However, we would probably not want to burden all loops with the exception-handling machinery, so the compiler would have to do some hacky backtracking (I doubt that the arbitrary lookahead needed to handle "maybe we got some except clauses coming?" during parsing would be acceptable) and fill that in *after* recognizing that there are except clauses in this for statement.
Would it be so bad to simply wrap for loops with except clauses automatically that can be clobbered or not? e.g.
for x in iterable: ...
really does something like this
try:
for x in iterable:
... except Exception: raise
Meaning that it doesn't need to wait to see if it does and backtrace but can just trust that there will be the default reraise? Apologies if this is a stupid question. Second, generally Python tries to avoid overloading keywords with
multiple semantics. The potential for confusion and misunderstanding of "except" (which I've suggested myself and now dislike) is pretty large I think.
I am not sure I follow you here since the `except` is being used in the same way as in `try...except` so I wouldn't expect a high potential for confusion, although I suppose that is, ironically, the same line of thinking as with `for...else`.
It might be possible to save that level of indentation with this syntax:
try for elem in iterable: ... if should_break(elem): raise SomeException except SomeException as e: handle_break_behaviour(e) else: print("Did not break")
(and I suppose you could do the same for any control flow statement, although I'm not sure offhand that the various keywords are 100% disjoint -- that would need to be checked). But I don't think it's worth it. I don't see enough benefits from this mixing of try and for to make it worth the complexity.
I agree that this seems to add some complexity but I actually like this a lot. It would surely also address the issue of the parser knowing it should be looking for exceptions or not?
I (and others) have suggested this before and no one has said it's a *bad *option,
It is, though, for the reasons above as well as the reasons Rob gives in his parallel followup.
Thank you, I appreciate it at least being addressed! -- 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 06/08/2020 08:57, Stephen J. Turnbull wrote:
Mathew Elman writes:
Being able to break multiple loops and having "labelled" breaks would be achievable using `except`, i.e. adding `except` to the loop statements before `else` like this:
This would certainly be consistent with the existing use of the except keyword, unlike the proposal to have it take both exceptions (in 'try' statements) and break labels (in 'for' and 'while' statements).
However, we would probably not want to burden all loops with the exception-handling machinery, so the compiler would have to do some hacky backtracking (I doubt that the arbitrary lookahead needed to handle "maybe we got some except clauses coming?" during parsing would be acceptable) and fill that in *after* recognizing that there are except clauses in this for statement.
Did you see Guido's post when I raised a similar object to detecting "zero iterations", where it would be unacceptable to slow down all for-loops, so they would have to be compiled differently? I wrote (in ignorance:-)): So: You're asking that the bytecode generated for the for-loop depends on something that happens (or not) after the end of the for-loop body (which could be arbitrarily long). I speak from ignorance, but I suspect that even with the new parser, which I am reliably informed can make the tea and implement world peace, that would be asking a lot. Guido replied: Rest assured this is not a problem. In any case it’s the compiler, not the parser, that generates the bytecode, from the AST. The compiler always has the full AST available before it is asked to generate any bytecode. The new parser just allows more flexible syntactic constructs, esp. “soft keywords”.
Second, generally Python tries to avoid overloading keywords with multiple semantics. The potential for confusion and misunderstanding of "except" (which I've suggested myself and now dislike) is pretty large I think.
IMO this is a bit disingenuous: "as" can be used with "import" and with context managers with quite different semantics. "del" can be used to remove a variable binding, a sequence element, a sequence slice or a dictionary key. "not" can be used as Boolean negation or in the compound operator "not in". Whereas the new use of "except" that Matthew is proposing is very similar to its existing use (certainly conceptually, if not in the implementation details).
It might be possible to save that level of indentation with this syntax:
try for elem in iterable: ... if should_break(elem): raise SomeException except SomeException as e: handle_break_behaviour(e) else: print("Did not break")
(and I suppose you could do the same for any control flow statement, although I'm not sure offhand that the various keywords are 100% disjoint -- that would need to be checked). But I don't think it's worth it. I don't see enough benefits from this mixing of try and for to make it worth the complexity.
I (and others) have suggested this before and no one has said it's a *bad *option,
It is, though, for the reasons above as well as the reasons Rob gives in his parallel followup.
Steve
(To be clear: although I'm defending Matthew's proposal here, my preferred option is still some new syntax.)
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/OVRYSB... Code of Conduct: http://python.org/psf/codeofconduct/
Rob Cliffe writes:
Did you see Guido's post when I raised a similar object to detecting "zero iterations", where it would be unacceptable to slow down all for-loops, so they would have to be compiled differently?
Yes. My confusion (as you'll see elsewhere) was about the AST, not the parser.
Second, generally Python tries to avoid overloading keywords with multiple semantics. The potential for confusion and misunderstanding of "except" (which I've suggested myself and now dislike) is pretty large I think.
IMO this is a bit disingenuous:
I'm not trying to mislead anybody, or try to imply there aren't cases where keywords have been repurposed.
"as" can be used with "import" and with context managers with quite different semantics.
I would disagree that the semantics are different. Context managers and imports have quite different semantics, but in both cases the "as" clause has name binding semantics, while the object bound is determined by the statement, not by the "as" clause.
"del" can be used to remove a variable binding, a sequence element, a sequence slice or a dictionary key.
The connection is more tenuous, but in each case an object loses a reference. I see your point of view, especially since the semantics of del on sequence elements and slices affects the "names" of other sequence elements, but I think the "reference destruction" semantics are "sufficiently" similar across the different uses of "del".
"not" can be used as Boolean negation or in the compound operator "not in".
Which is a negation. I don't see how anybody reading that could mistake the meaning.
Whereas the new use of "except" that Matthew is proposing is very similar to its existing use (certainly conceptually, if not in the implementation details).
As a restricted goto, that is true. In fact, it's so similar that we may as well use the original! Is one level of indentation really worth it? What I see as different is that Matthew's proposal is for a purpose that is explicitly local to the loop statement, where except is explicitly nonlocal. Another way to put it is in this thread "except" is proposed as marking a goto target, where in a try "except" is almost a "come from" (although not with full INTERCAL compatility). I also wonder about try ... excepts nested in a for loop with excepts. That's probably no harder to deal with than nested loops with breaks at different levels (but that can be a bit confusing).
(To be clear: although I'm defending Matthew's proposal here, my preferred option is still some new syntax.)
"try" is enough to implement any of the use cases in the relatively rare cases it's needed. On the plus side, a "try" and its except clauses require a bit of code to set up. I don't know whether that's a major consideration, but one advantage of a new implementation for the purpose of implementing "labelled breaks" would be to have a lighter implementation. Whether it's worth it is above my pay grade.
On Thu, Aug 6, 2020 at 01:00 Stephen J. Turnbull < turnbull.stephen.fw@u.tsukuba.ac.jp> wrote:
However, we would probably not want to burden all loops with the exception-handling machinery, so the compiler would have to do some hacky backtracking (I doubt that the arbitrary lookahead needed to handle "maybe we got some except clauses coming?" during parsing would be acceptable) and fill that in *after* recognizing that there are except clauses in this for statement.
Maybe you’re thinking of a “one-pass” compiler, like the original Pascal compiler, that generates code during parsing. That’s not how modern compilers work anymore. :-) The parser builds an AST, and the code generator uses the whole AST as input. It would not be “hacky” for the compiler to generate different code for the first half of a compound statement depending on how it ends. (However, it *would* be hacky to vary based on whether a statement was followed by a certain other statement, as that would require going “up” in the AST.) —Guido -- --Guido (mobile)
Guido van Rossum writes:
Maybe you’re thinking of a “one-pass” compiler, like the original Pascal compiler, that generates code during parsing.
Not really. The "after" phrasing comes from the parsing part which does move through the source pretty much linearly in both the traditional and PEG parsers (as far as I understand the latter). What I really meant with respect to the code generation was what you describe as "going 'up'" with respect to the AST. Evidently I got that wrong. I have a somewhat nebulous understanding of which way is "up", I guess. :-) I need to go back to school on compiler tech.
On Wed, Jul 29, 2020 at 02:51 Mathew Elman <mathew.elman@ocado.com> wrote:
.
If it *is* useful, it occurs to me that (1) this looks a lot like the try ... except ... pattern, and (2) breaks are generally perceived as exceptional exits from a loop. Instead of "if break [LABEL]", "except [LABEL]" might work, although the semantic difference between labels and exceptions might get a ton of pushback.
...
Steve
In the related thread I suggested using `except`, but it was largely ignored.
*If* you want tou propose clearer syntax for this, please extend the loop
syntax, not the ‘if’ syntax. So, ‘case ... zero’ makes more sense than ‘if [not] break’.
—Guido
So I understand, does this mean that any extended syntax for this should be *totally* new and not draw on existing constructs such as `try-except` or `if-else`? Or just that the additional clarity should come from extending the loop rather than the implicit `if`?
Actually, given that ‘else:’ already confuses people I very much doubt that any other new construct will be acceptable. It is totally five not to “solve” this problem at all — all use cases can be done by adding flag variables explicitly manipulated by the user’s code.
Mathew
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. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/TVTCXQ... Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido (mobile)
On Wed, 29 Jul 2020 at 14:42, Guido van Rossum <guido@python.org> wrote:
On Wed, Jul 29, 2020 at 02:51 Mathew Elman <mathew.elman@ocado.com> wrote:
.
If it *is* useful, it occurs to me that (1) this looks a lot like the try ... except ... pattern, and (2) breaks are generally perceived as exceptional exits from a loop. Instead of "if break [LABEL]", "except [LABEL]" might work, although the semantic difference between labels and exceptions might get a ton of pushback.
...
Steve
In the related thread I suggested using `except`, but it was largely ignored.
*If* you want tou propose clearer syntax for this, please extend the loop
syntax, not the ‘if’ syntax. So, ‘case ... zero’ makes more sense than ‘if [not] break’.
—Guido
So I understand, does this mean that any extended syntax for this should be *totally* new and not draw on existing constructs such as `try-except` or `if-else`? Or just that the additional clarity should come from extending the loop rather than the implicit `if`?
Actually, given that ‘else:’ already confuses people I very much doubt that any other new construct will be acceptable. It is totally five not to “solve” this problem at all — all use cases can be done by adding flag variables explicitly manipulated by the user’s code.
I understand that the "problem" with `else` is aesthetic, though one could debate the importance of such a problem. What I mean to ask is, for example, would having `for-except-else` (analogous to `try-except-else`) be an acceptable extension of "the loop syntax, not the ‘if’ syntax"?
Mathew
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. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/TVTCXQ... Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido (mobile)
-- 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, Jul 29, 2020 at 07:01 Mathew Elman <mathew.elman@ocado.com> wrote:
On Wed, 29 Jul 2020 at 14:42, Guido van Rossum <guido@python.org> wrote:
On Wed, Jul 29, 2020 at 02:51 Mathew Elman <mathew.elman@ocado.com> wrote:
.
If it *is* useful, it occurs to me that (1) this looks a lot like the try ... except ... pattern, and (2) breaks are generally perceived as exceptional exits from a loop. Instead of "if break [LABEL]", "except [LABEL]" might work, although the semantic difference between labels and exceptions might get a ton of pushback.
...
Steve
In the related thread I suggested using `except`, but it was largely ignored.
*If* you want tou propose clearer syntax for this, please extend the
loop syntax, not the ‘if’ syntax. So, ‘case ... zero’ makes more sense than ‘if [not] break’.
—Guido
So I understand, does this mean that any extended syntax for this should be *totally* new and not draw on existing constructs such as `try-except` or `if-else`? Or just that the additional clarity should come from extending the loop rather than the implicit `if`?
Actually, given that ‘else:’ already confuses people I very much doubt that any other new construct will be acceptable. It is totally five not to “solve” this problem at all — all use cases can be done by adding flag variables explicitly manipulated by the user’s code.
I understand that the "problem" with `else` is aesthetic, though one could debate the importance of such a problem.
What I mean to ask is, for example, would having `for-except-else` (analogous to `try-except-else`) be an acceptable extension of "the loop syntax, not the ‘if’ syntax"?
I honestly and strongly believe that we should do nothing here. Python thrives because it is relatively simple. Adding new syntax to deal with looping special cases makes it less simple, and encourages a bad coding style (nested loops, multiple breaks...).
Mathew
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. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/TVTCXQ... Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido (mobile)
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. _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/YTC6Z4... Code of Conduct: http://python.org/psf/codeofconduct/
-- --Guido (mobile)
On 2020-07-29 at 07:09:05 -0700, Guido van Rossum <guido@python.org> wrote:
I honestly and strongly believe that we should do nothing here. Python thrives because it is relatively simple. Adding new syntax to deal with looping special cases makes it less simple, and encourages a bad coding style (nested loops, multiple breaks...).
I was about to go off on another Get Off My Lawn rant, so thank you for putting this so succintly and so politely. :-) If I end up with more than one flag controlling my search loop, then it's time to break (pun intended) the logic into smaller/simpler pieces rather than to look for a more complicated language construct.
Guido wrote: I honestly and strongly believe that we should do nothing here. Python
thrives because it is relatively simple. Adding new syntax to deal with looping special cases makes it less simple, and encourages a bad coding style (nested loops, multiple breaks...).
I agree with about 80% of this statement. In particular I believe strongly that we should do nothing here, without strong evidence that the change will bring at least significant benefit to some users, and no or very little harm to the rest. I also believe that meeting that criteria is only the first step. It is quite possible for a reasonable request for change to be reasonably refused. Again, I believe that one reason why Python thrives is that it is relatively simple for novices. Another reason is that it provides facilities such as __dunder__ methods and metaclasses, so that experts can do advanced things. List comprehensions perhaps lie somewhere in between. From a syntactic point of view, I think it important that we do what we can to avoid novices accidentally encountering an advanced feature. Here's an example. PEP 622 -- Structural Pattern Matching suggests introducing a language feature that, I think, most novices will find hard to understand properly. But it seems that experts will like it's power and simplicity, for doing some advanced things. PEP 622 introduces new keywords 'match' and 'case'. The new keywords make it easy for us to warn novices not to use it (and we don't put it in the beginners tutorial). Here's the example from the PEP. def make_point_3d(pt): match pt: case (x, y): return Point3d(x, y, 0) case (x, y, z): return Point3d(x, y, z) case Point2d(x, y): return Point3d(x, y, 0) case Point3d(_, _, _): return pt case _: raise TypeError("not a point we support") Some conditions necessary for "break to a label" to be accepted are strong use cases, and a syntax that keeps the construction out of the hands of the novices. These conditions are not sufficient. I intend to keep my eyes open, as I go about my daily activities, of strong use cases. If I don't see any, then most likely you won't hear anything more from me on this suggestion. -- Jonathan
participants (7)
-
2QdxY4RzWzUUiLuE@potatochowder.com
-
Dominik Vilsmeier
-
Guido van Rossum
-
Jonathan Fine
-
Mathew Elman
-
Rob Cliffe
-
Stephen J. Turnbull