if condition: break idiom

Hello, It seems to me that a lot of the time that I use a break statement, it is directly after an if. Typically: while True: do something if condition: break do something else I don't like so much the if .. break which is spread over two lines. Of course I could write while True: do something if condition: break do something else It doesn't read so well either IMHO. I think that this would look better: while True: do something break if condition do something else Now I've had a quick look on a py3k tree (a bit old, rev. 64270): $ grep -r --include "*.py" break py3k/ | wc -l 1418 1418 uses of the break statement in the py3k python code. $ grep -r --include "*.py" -B 1 break py3k/ | grep if | wc -l 680 Of which 680 are immediately preceded by an if statement $ grep -r --include "*.py" "if .*: break" py3k/ | wc -l 107 Of which 107 are preceded by an if on the same line This means that: * 48% of uses of "break" are directly after an "if" * this has been written on one single line about 16% of the time. (I know my greps will include a few false positive but I don't think they are significant :) -- Arnaud

On Sat, Sep 20, 2008 at 11:35 AM, Arnaud Delobelle <arnodel@googlemail.com> wrote:
For some reason this suggestion reminds me of Icon. Anyway, so I take it this suggestion is to extend the break statement to have an 'if' trailer? Or are you trying to make 'break' an expression? If you are after the former, the problem with that is that the special-casing of 'if' might confuse people because they will suddenly want an 'else' clause. Adding that might then cause a naive user to see ``break if x`` and then think 'break' is an expression. Which leads to its own issues. How do you implement 'break' as an expression? It doesn't make much sense to have ``fxn(a, break, b)`` inside a loop. And you can't say 'break' can only appear in the true clause of an 'if' expression as that is too specialized and will lead to potential misuse of the statement (or at least an attempt). I don't see enough benefit from the change to warrant dealing with any of the above issues. -Brett

On Sat, Sep 20, 2008 at 12:07 PM, Brett Cannon <brett@python.org> wrote:
It gets worse ;) break if condition Also implies... continue if condition Never mind break if condition else continue continue if condition else break Because who would want to write... break if condition continue or continue if condition break But if we can break or continue, why not others? What's wrong with a raise (especially if we surround everything with parens...)? (raise Exception("X")) if condition Never mind assert, yield, throw, return, ... I hope this horse is dead now. - Josiah

On 20 Sep 2008, at 20:44, Josiah Carlson wrote:
That's true, why not? I don't use use continue so much but it seems logical.
No that would be silly.
The problem is: when would you need to do this? I pointed out in my original post that almost half of uses of 'break' in the py3k python source come immediately after an 'if'. Now I have never used or seen this: if condition: break continue What would be the point of spelling it 'break if condition else continue'? It would even defeat the idea behind my suggestion, which is to make the structure of a loop more obvious when you scan code: you can spot the 'break if' (and 'continue if'!) statements just by scanning the left hand side of the loop body.
You have implied one reason why not: raise, assert, yield, throw, return all take an argument which can be an if-expression, so this would make those statements difficult to parse if you are human (and I suspect impossible if you are the Python parser). The fact that neither break nor continue take arguments makes them very 'poor' in the amount of meaning they convey. That's why a lot of people feel like writing the following in one single line. if condition: break Moreover, because we don't have a 'do .. while' construct, 'break' is more important than in other languages to shape loops (especially while loops), so I thought it would be useful to make it easier to spot. The same argument can be made about 'continue' of course.
- Josiah
-- Arnaud

On Sat, Sep 20, 2008 at 1:26 PM, Arnaud Delobelle <arnodel@googlemail.com> wrote:
Why? It follows directly from conditional expressions as well as your proposed syntax?
Just because *you've* never seen it, doesn't mean it shouldn't be a valid control structure. while ...: #do some stuff if some_condition: #do some other stuff break if other_condition else continue #do yet some other stuff which is skipped by the line above You are probably thinking; "but Josiah, that secondary clause could be held in an else clause", and I would confirm that. But then I would point out that this one example cannot possibly encompass the entirety of potential uses for the feature. I would then point out that the cases that you are trying to fix, 'break if condition', you inadvertently hide the *flow control* in a mass of words. Break and continue are currently happy little single-word statements. Even when trailing on the same line as an 'if', there is a colon separating them from the if and condition. I would argue that this punctuation is critical for understanding the idea "something conditional is happening here to your flow control". Without that colon, break/continue get to be the only two statements that get an optional 'if' suffix, whose only purpose seems to be to reduce line count.
But this doesn't help in that. Break and continue are *already* immediately to the right of whitespace (unless someone tries to make it a single line), and while the *simple* case of... for ... in ...: ... if condition: break ... ... is common, that doesn't mean that the following isn't ... for ... in ...: ... if condition: ... if other_condition: break ... ... Which isn't greatly improved by your suggestion.
No, I pointed out a syntax that is unambiguous. How do I know it is unambiguous? Because it's used by the yield *expression* in Python 2.5 and later: x = (yield y) + 1 Though maybe that's a vote against yield, because the rest are statements and don't return anything.
It's not a question of amount of meaning, it's a question of context. I've heard explanations at least as much saying that they thought that not having an indented trailer makes the code "prettier", "shorter", "easier to understand" as I've heard the opposite from reviewers arguing against the single-line if idiom.
Perfectly reasonable, but then the base isn't so much... while 1: ... if condition: break ... it's really... while 1: ... if condition: break Which *has* an idiom in Python. first = 1 while first or condition: first = 0 ... And before you come back with "but that's not as fast", I'll point out that an assignment to a local and an or computation are pretty darn fast. With psyco; even faster:
Worst-case, 15% more time without psyco for the *simplest* possible loop. Less difference as the body of the while increases. With psyco: no difference. But what about, "that's not as pretty as 'break if condition'"? Ok, it's not as pretty. But I would then point out that at least now, you don't have one of those "while 1:" loops that can raise eyebrows. - Josiah

On 21 Sep 2008, at 19:36, Terry Reedy wrote:
I don't know what was the motivation for including conditional expression in the language, but: condition and x or y is better replaced with: x if condition else y So from a pragmatic point of view, if-expressions work as some kind of "vaccine" against the above. -- Arnaud

On 21 Sep 2008, at 17:48, Josiah Carlson wrote:
I don't think it does. This has nothing to do with conditional expressions.
What I'm saying is that it doesn't occur often enough to be worried about it. OTOH, 'if condition: break' occurs very commonly. [...]
Reducing line count was definitely not my aim (see just below)
You forget: if condition: break
There's some truth in this.
Yes, they're statements, I wouldn't want them to be surrounded by parentheses. I only proposed "break if" (and "continue if", perhaps), I don't see why every statement should be equipped with a trailing "if" as a necessary consequence.
if condition: break on a single line happens a lot, whether liked by reviewers or not.
I don't agree with that: the absence of do .. while liberates the loop construct in python from its constraints and the first form above becomes more common.
I would not use this, not because it is slower, but because it is uglier.
My tests:
test1 is 41% faster, that is not negligible. I don't think the fact that psyco optimises the code is a valid argument.
Well, they don't raise my eyebrows :)
- Josiah
Anyway, there hasn't been a flurry of positive responses so far so I don't think this is going to go much further than this reply... -- Arnaud

On 20 Sep 2008, at 20:07, Brett Cannon wrote:
No I wasn't suggesting this.
I thought that the meaning of e.g. break if x < 1 was clear and unambiguous. I don't know if some people do, but I personally have never felt the need to write something like: expression1 if condition else expression2 on its own on a line. So I wouldn't find the above 'break if x < 1' statement confusing :)
I certainly wouldn't want 'break' to be an expression.
I don't see enough benefit from the change to warrant dealing with any of the above issues.
Fair enough!
-Brett
-- Arnaud

Arnaud Delobelle wrote:
I think mid-test/multi-test loops are common enough that it might be worth explicit syntax to pick out the loop exit points: while True: do something andwhile not condition: do something else (or 'and while' if one wanted to save on reserved words. 'not condition' because the logic is reversed from the quoted example.) Similarly for 'if', I often find myself with unsatisfactory constructs like: if condition: do something if othercondition: success else: failure else: failure I would like to flatten together the else clauses: if condition: do something andif othercondition: success else: failure

On Thu, Sep 25, 2008 at 6:34 AM, Andrew Clover <and-dev@doxdesk.com> wrote:
That breaks the flow of the loop, and it is not visually clear that "do something else" is a part of the while loop. This is one of many reasons why switch/case statements failed.
That becomes ambiguous in the case of more than 2 levels of if, never mind needing andelif, never mind being wholly unreadable by non-english speakers. Flat is better than nested, but nested indents do offer clarity about what code does. A brief skimming of the above tells me nothing about the control flow of the code. - Josiah

Josiah Carlson wrote:
while True: do something *breakif condition do something else *continueif condition do some other thing I don't know if you can start a key word with * but it does pick out the loop exit points without complicating the indentation. Is it terribly bad? It was rejected a few months ago, but possibly because it was lumped in with some other stuff. The only alternative I can think of is syntax colouring: recommend that keywords that break the flow should be treated differently from other keywords in Python code editors. eg break, continue, return, exit in bold red. -- jh

On Sat, Sep 20, 2008 at 11:35 AM, Arnaud Delobelle <arnodel@googlemail.com> wrote:
For some reason this suggestion reminds me of Icon. Anyway, so I take it this suggestion is to extend the break statement to have an 'if' trailer? Or are you trying to make 'break' an expression? If you are after the former, the problem with that is that the special-casing of 'if' might confuse people because they will suddenly want an 'else' clause. Adding that might then cause a naive user to see ``break if x`` and then think 'break' is an expression. Which leads to its own issues. How do you implement 'break' as an expression? It doesn't make much sense to have ``fxn(a, break, b)`` inside a loop. And you can't say 'break' can only appear in the true clause of an 'if' expression as that is too specialized and will lead to potential misuse of the statement (or at least an attempt). I don't see enough benefit from the change to warrant dealing with any of the above issues. -Brett

On Sat, Sep 20, 2008 at 12:07 PM, Brett Cannon <brett@python.org> wrote:
It gets worse ;) break if condition Also implies... continue if condition Never mind break if condition else continue continue if condition else break Because who would want to write... break if condition continue or continue if condition break But if we can break or continue, why not others? What's wrong with a raise (especially if we surround everything with parens...)? (raise Exception("X")) if condition Never mind assert, yield, throw, return, ... I hope this horse is dead now. - Josiah

On 20 Sep 2008, at 20:44, Josiah Carlson wrote:
That's true, why not? I don't use use continue so much but it seems logical.
No that would be silly.
The problem is: when would you need to do this? I pointed out in my original post that almost half of uses of 'break' in the py3k python source come immediately after an 'if'. Now I have never used or seen this: if condition: break continue What would be the point of spelling it 'break if condition else continue'? It would even defeat the idea behind my suggestion, which is to make the structure of a loop more obvious when you scan code: you can spot the 'break if' (and 'continue if'!) statements just by scanning the left hand side of the loop body.
You have implied one reason why not: raise, assert, yield, throw, return all take an argument which can be an if-expression, so this would make those statements difficult to parse if you are human (and I suspect impossible if you are the Python parser). The fact that neither break nor continue take arguments makes them very 'poor' in the amount of meaning they convey. That's why a lot of people feel like writing the following in one single line. if condition: break Moreover, because we don't have a 'do .. while' construct, 'break' is more important than in other languages to shape loops (especially while loops), so I thought it would be useful to make it easier to spot. The same argument can be made about 'continue' of course.
- Josiah
-- Arnaud

On Sat, Sep 20, 2008 at 1:26 PM, Arnaud Delobelle <arnodel@googlemail.com> wrote:
Why? It follows directly from conditional expressions as well as your proposed syntax?
Just because *you've* never seen it, doesn't mean it shouldn't be a valid control structure. while ...: #do some stuff if some_condition: #do some other stuff break if other_condition else continue #do yet some other stuff which is skipped by the line above You are probably thinking; "but Josiah, that secondary clause could be held in an else clause", and I would confirm that. But then I would point out that this one example cannot possibly encompass the entirety of potential uses for the feature. I would then point out that the cases that you are trying to fix, 'break if condition', you inadvertently hide the *flow control* in a mass of words. Break and continue are currently happy little single-word statements. Even when trailing on the same line as an 'if', there is a colon separating them from the if and condition. I would argue that this punctuation is critical for understanding the idea "something conditional is happening here to your flow control". Without that colon, break/continue get to be the only two statements that get an optional 'if' suffix, whose only purpose seems to be to reduce line count.
But this doesn't help in that. Break and continue are *already* immediately to the right of whitespace (unless someone tries to make it a single line), and while the *simple* case of... for ... in ...: ... if condition: break ... ... is common, that doesn't mean that the following isn't ... for ... in ...: ... if condition: ... if other_condition: break ... ... Which isn't greatly improved by your suggestion.
No, I pointed out a syntax that is unambiguous. How do I know it is unambiguous? Because it's used by the yield *expression* in Python 2.5 and later: x = (yield y) + 1 Though maybe that's a vote against yield, because the rest are statements and don't return anything.
It's not a question of amount of meaning, it's a question of context. I've heard explanations at least as much saying that they thought that not having an indented trailer makes the code "prettier", "shorter", "easier to understand" as I've heard the opposite from reviewers arguing against the single-line if idiom.
Perfectly reasonable, but then the base isn't so much... while 1: ... if condition: break ... it's really... while 1: ... if condition: break Which *has* an idiom in Python. first = 1 while first or condition: first = 0 ... And before you come back with "but that's not as fast", I'll point out that an assignment to a local and an or computation are pretty darn fast. With psyco; even faster:
Worst-case, 15% more time without psyco for the *simplest* possible loop. Less difference as the body of the while increases. With psyco: no difference. But what about, "that's not as pretty as 'break if condition'"? Ok, it's not as pretty. But I would then point out that at least now, you don't have one of those "while 1:" loops that can raise eyebrows. - Josiah

On 21 Sep 2008, at 19:36, Terry Reedy wrote:
I don't know what was the motivation for including conditional expression in the language, but: condition and x or y is better replaced with: x if condition else y So from a pragmatic point of view, if-expressions work as some kind of "vaccine" against the above. -- Arnaud

On 21 Sep 2008, at 17:48, Josiah Carlson wrote:
I don't think it does. This has nothing to do with conditional expressions.
What I'm saying is that it doesn't occur often enough to be worried about it. OTOH, 'if condition: break' occurs very commonly. [...]
Reducing line count was definitely not my aim (see just below)
You forget: if condition: break
There's some truth in this.
Yes, they're statements, I wouldn't want them to be surrounded by parentheses. I only proposed "break if" (and "continue if", perhaps), I don't see why every statement should be equipped with a trailing "if" as a necessary consequence.
if condition: break on a single line happens a lot, whether liked by reviewers or not.
I don't agree with that: the absence of do .. while liberates the loop construct in python from its constraints and the first form above becomes more common.
I would not use this, not because it is slower, but because it is uglier.
My tests:
test1 is 41% faster, that is not negligible. I don't think the fact that psyco optimises the code is a valid argument.
Well, they don't raise my eyebrows :)
- Josiah
Anyway, there hasn't been a flurry of positive responses so far so I don't think this is going to go much further than this reply... -- Arnaud

On 20 Sep 2008, at 20:07, Brett Cannon wrote:
No I wasn't suggesting this.
I thought that the meaning of e.g. break if x < 1 was clear and unambiguous. I don't know if some people do, but I personally have never felt the need to write something like: expression1 if condition else expression2 on its own on a line. So I wouldn't find the above 'break if x < 1' statement confusing :)
I certainly wouldn't want 'break' to be an expression.
I don't see enough benefit from the change to warrant dealing with any of the above issues.
Fair enough!
-Brett
-- Arnaud

Arnaud Delobelle wrote:
I think mid-test/multi-test loops are common enough that it might be worth explicit syntax to pick out the loop exit points: while True: do something andwhile not condition: do something else (or 'and while' if one wanted to save on reserved words. 'not condition' because the logic is reversed from the quoted example.) Similarly for 'if', I often find myself with unsatisfactory constructs like: if condition: do something if othercondition: success else: failure else: failure I would like to flatten together the else clauses: if condition: do something andif othercondition: success else: failure

On Thu, Sep 25, 2008 at 6:34 AM, Andrew Clover <and-dev@doxdesk.com> wrote:
That breaks the flow of the loop, and it is not visually clear that "do something else" is a part of the while loop. This is one of many reasons why switch/case statements failed.
That becomes ambiguous in the case of more than 2 levels of if, never mind needing andelif, never mind being wholly unreadable by non-english speakers. Flat is better than nested, but nested indents do offer clarity about what code does. A brief skimming of the above tells me nothing about the control flow of the code. - Josiah

Josiah Carlson wrote:
while True: do something *breakif condition do something else *continueif condition do some other thing I don't know if you can start a key word with * but it does pick out the loop exit points without complicating the indentation. Is it terribly bad? It was rejected a few months ago, but possibly because it was lumped in with some other stuff. The only alternative I can think of is syntax colouring: recommend that keywords that break the flow should be treated differently from other keywords in Python code editors. eg break, continue, return, exit in bold red. -- jh
participants (6)
-
Andrew Clover
-
Arnaud Delobelle
-
Brett Cannon
-
Jim Hill
-
Josiah Carlson
-
Terry Reedy