I propose that in Py3.0, the "and" and "or" operators be simplified to always return a Boolean value instead of returning the last evaluated argument. 1) The construct can be error-prone. When an error occurs it can be invisible to the person who wrote it. I got bitten in published code that had survived testing and code review: def real(self): 'Return a vector with the real part of each input element' # do not convert integer inputs to floats return self.map(lambda z: type(z)==types.ComplexType and z.real or z) The code fails silently when z is (0+4i). It took a good while to trace down a user reported error (when Matlab results disagreed with my matrix module results) and determine that the real() method contained an error. Even when traced down, I found it hard to see the error in the code. Now that I know what to look for, it has not happened again, but I do always have to stare hard at any "and/or" group to mentally verify each case. 2) When going back and forth between languages, it is easy to forget that only Python returns something other than a boolean. 3) Even when it isn't being used, the possibility of non-boolean return value complicates the bytecode and parser. To allow for "and/or", the conditional opcodes leave the tested value on the stack. In most cases both branches go directly to a POP_TOP instruction. Since the POP_TOP shouldn't be executed twice, the body of the positive branch has to close with a jump over the other branch even when it is empty. For instance, the simplest case: if a: b compiles to: 1 0 LOAD_NAME 0 (a) 3 JUMP_IF_FALSE 8 (to 14) 6 POP_TOP 2 7 LOAD_NAME 1 (b) 10 POP_TOP 11 JUMP_FORWARD 1 (to 15) >> 14 POP_TOP >> 15 LOAD_CONST 0 (None) 18 RETURN_VALUE this could be simpler and faster: 1 0 LOAD_NAME 0 (a) 3 JUMP_IF_FALSE 8 (to 10) 2 6 LOAD_NAME 1 (b) 9 POP_TOP >> 10 LOAD_CONST 0 (None) 13 RETURN_VALUE Executive summary. Returning only Booleans reduces errors, makes the code easier to review, follows other language norms, and simplifies/speeds-up the generated code. Raymond P.S. Simplifying "and" and "or" may create a need to introduce a conditional operator but that is a discussion for another day.
On 9/19/05, Raymond Hettinger
I propose that in Py3.0, the "and" and "or" operators be simplified to always return a Boolean value instead of returning the last evaluated argument.
While you're at it, maybe we should switch to && and || as well? That's another thing I always mistype when switching between languages... Also, this proposal needs to be considered together with the addition of a proper conditional operator, like x?y:z. -- --Guido van Rossum (home page: http://www.python.org/~guido/)
On Mon, 2005-09-19 at 20:03, Guido van Rossum wrote:
While you're at it, maybe we should switch to && and || as well? That's another thing I always mistype when switching between languages...
Please no! 'and' and 'or' is so readably beautiful.
Also, this proposal needs to be considered together with the addition of a proper conditional operator, like x?y:z.
Definitely. -Barry
On 9/19/05, Barry Warsaw
On Mon, 2005-09-19 at 20:03, Guido van Rossum wrote:
While you're at it, maybe we should switch to && and || as well? That's another thing I always mistype when switching between languages...
Please no! 'and' and 'or' is so readably beautiful.
I completely agree.
Also, this proposal needs to be considered together with the addition of a proper conditional operator, like x?y:z.
Definitely.
Yep. -Brett
Guido van Rossum
On 9/19/05, Raymond Hettinger
wrote: I propose that in Py3.0, the "and" and "or" operators be simplified to always return a Boolean value instead of returning the last evaluated argument.
While you're at it, maybe we should switch to && and || as well? That's another thing I always mistype when switching between languages...
You're joking, surely?
Also, this proposal needs to be considered together with the addition of a proper conditional operator, like x?y:z.
I think this discussion has been had before, you know. Cheers, mwh --
Look I don't know. Thankyou everyone for arguing me round in circles. No need for thanks, ma'am; that's what we're here for. -- LNR & Michael M Mason, cam.misc
Michael Hudson wrote:
While you're at it, maybe we should switch to && and || as well? That's another thing I always mistype when switching between languages...
You're joking, surely?
for Python 3000, I'd recommend switching to "and then" and "or else" instead of the current ambiguous single-keyword versions. </F>
While you're at it, maybe we should switch to && and || as well? That's another thing I always mistype when switching between languages...
You're joking, surely?
for Python 3000, I'd recommend switching to "and then" and "or else" instead of the current ambiguous single-keyword versions.
Wouldn't it be possible to omit "and" and "or" to just "then" and "else"? x = 3 and 7 or 44 x = 3 and then 7 or else 44 x = 3 then 7 else 44 And then have another set of and and or for non short-circuiting? -- mvh Björn
BJörn Lindqvist wrote:
Wouldn't it be possible to omit "and" and "or" to just "then" and "else"?
x = 3 and 7 or 44 x = 3 and then 7 or else 44 x = 3 then 7 else 44
And then have another set of and and or for non short-circuiting?
I don't think the OP was suggesting that 'and' and 'or' be non-short-circuiting, only that they coerce their evaluated operands to bool. Short-circuiting vs. non-short-circuiting is an orthogonal issue. -- Greg Ewing, Computer Science Dept, +--------------------------------------+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | greg.ewing@canterbury.ac.nz +--------------------------------------+
Fredrik Lundh wrote:
Michael Hudson wrote:
While you're at it, maybe we should switch to && and || as well? That's another thing I always mistype when switching between languages...
You're joking, surely?
for Python 3000, I'd recommend switching to "and then" and "or else" instead of the current ambiguous single-keyword versions.
</F>
Keeping the current behaviors in some form would probably be good. Alternate operators might be a good way. They could also be functions. first_true(a, b, c) <--- a and b and d true_else(a, b) <--- a or b This would compliment: all_true(a, b, c) none_true(a, b, c) The '?' could just be used in place of the current 'or' and the '*' would work as "and value" operator when used with bools. val = a ? b ? c # val = a or b or c val = a and b * c # val = bool(a and b) and c val = a or b * c ? d # val = bool(a or b) and c or d And a vague idea of a suggestion... For the function versions above ... If speed or the need to avoid early evaluation is a concern, one thought would be to have a few "well selected" builtin C tuple operators that look and act like functions but are instead optimized operations. Functions that don't use any intermediate values and/or are so simple that the function call is large percent of the overall execution time could be candidates. It also might be possible to avoid early evaluation in cases where it makes since to do so. Just a thought. I have no idea how hard this would be, and since one of the goals of Python 3000 is to simplify and/or clean up the core, this might not be desirable. Cheers, Ron
Fredrik Lundh wrote:
for Python 3000, I'd recommend switching to "and then" and "or else" instead of the current ambiguous single-keyword versions.
And then we could call the language Pyffel. :-) -- Greg Ewing, Computer Science Dept, +--------------------------------------+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | greg.ewing@canterbury.ac.nz +--------------------------------------+
On 9/20/05, Michael Hudson
Guido van Rossum
writes: On 9/19/05, Raymond Hettinger
wrote: I propose that in Py3.0, the "and" and "or" operators be simplified to always return a Boolean value instead of returning the last evaluated argument.
While you're at it, maybe we should switch to && and || as well? That's another thing I always mistype when switching between languages...
You're joking, surely?
I wasn't, but I wasn't pushing for it either. Consider it withdrawn given the response.
Also, this proposal needs to be considered together with the addition of a proper conditional operator, like x?y:z.
I think this discussion has been had before, you know.
Unfortunately, if we were to accept Raymond's proposal, we'd have to revisit the discussion, since his proposal removes several ways we currently avoid the need. In fact, I think Raymond's example is more properly considered an argument for adding a conditional expression than for removing the current behavior of the and/or shortcut operators; had we had a conditional expression, he wouldn't have tried to use the "x and y or z" syntax that bit him. Given this realization, I'm now -1 on Raymond's idea, and +1 on adding a conditional expression. I believe (y if x else z) was my favorite last time, wasn't it? I've changed the subject accordingly. -- --Guido van Rossum (home page: http://www.python.org/~guido/)
Guido van Rossum
Unfortunately, if we were to accept Raymond's proposal, we'd have to revisit the discussion, since his proposal removes several ways we currently avoid the need.
In fact, I think Raymond's example is more properly considered an argument for adding a conditional expression than for removing the current behavior of the and/or shortcut operators; had we had a conditional expression, he wouldn't have tried to use the "x and y or z" syntax that bit him.
Indeed.
Given this realization, I'm now -1 on Raymond's idea, and +1 on adding a conditional expression. I believe (y if x else z) was my favorite last time, wasn't it? I've changed the subject accordingly.
It's not the version from the PEP, if that means anything at all... Cheers, mwh -- 34. The string is a stark data structure and everywhere it is passed there is much duplication of process. It is a perfect vehicle for hiding information. -- Alan Perlis, http://www.cs.yale.edu/homes/perlis-alan/quotes.html
Guido van Rossum wrote:
Given this realization, I'm now -1 on Raymond's idea, and +1 on adding a conditional expression. I believe (y if x else z) was my favorite last time, wasn't it? I've changed the subject accordingly.
As the PEP states, I'm not sure if changing the customary order of "arguments" in conditional expressions is good. Also, I assume the thing will be short-circuiting, and it's confusing to grasp that y in (y if x else z) will possibly never be evaluated. Reinhold -- Mail address is perfectly valid!
On Tue, Sep 20, 2005 at 09:04:53AM -0700, Guido van Rossum wrote:
On 9/20/05, Michael Hudson
wrote: Guido van Rossum
writes: On 9/19/05, Raymond Hettinger
wrote: I propose that in Py3.0, the "and" and "or" operators be simplified to always return a Boolean value instead of returning the last evaluated argument.
While you're at it, maybe we should switch to && and || as well? That's another thing I always mistype when switching between languages...
You're joking, surely?
I wasn't, but I wasn't pushing for it either. Consider it withdrawn given the response.
Also, this proposal needs to be considered together with the addition of a proper conditional operator, like x?y:z.
I think this discussion has been had before, you know.
Unfortunately, if we were to accept Raymond's proposal, we'd have to revisit the discussion, since his proposal removes several ways we currently avoid the need.
In fact, I think Raymond's example is more properly considered an argument for adding a conditional expression than for removing the current behavior of the and/or shortcut operators; had we had a conditional expression, he wouldn't have tried to use the "x and y or z" syntax that bit him.
Given this realization, I'm now -1 on Raymond's idea, and +1 on adding a conditional expression. I believe (y if x else z) was my favorite last time, wasn't it? I've changed the subject accordingly.
I'm +1 for allowing authors to write return bool(thing or default) when they mean a function to return a bool. I had the "privilege" of working in a large base of perl code (a learning experience) and while some engineers abused functions that were documented as only returning true/false by depending on the side effects of 'and' and 'or' this was easily fixed. The functions were changed to literally return a plain true or false value and those engineers were summarily fired. I'm a dependable Hettinger fanboy but on this one I have to agree with the we're-all-adults club. Let the authors type an extra few chars if they want to make the code match the intent. -jackdied
"Guido van Rossum"
In fact, I think Raymond's example is more properly considered an argument for adding a conditional expression than for removing the current behavior of the and/or shortcut operators; had we had a conditional expression, he wouldn't have tried to use the "x and y or z" syntax that bit him.
I agree.
Given this realization, I'm now -1 on Raymond's idea,
There are a lot of people who use 'or', especially, as intended.
and +1 on adding a conditional expression. I believe (y if x else z) was my favorite last time, wasn't it?
No. That was your original proposal, which you later rejected. "The original version of this PEP proposed the following syntax: <expression1> if <condition> else <expression2> The out-of-order arrangement was found to be too uncomfortable for many of participants in the discussion; especially when <expression1> is long, it's easy to miss the conditional while skimming." Your final 'favorite' was apparently (at the top) "Proposal The proposed syntax is as follows: (if <condition>: <expression1> else: <expression2>) " (+ elif parts) selected from "Summary of the Current State of the Discussion Groups are falling into one of three camps: 1. Adopt a ternary operator built using punctuation characters: <condition> ? <expression1> : <expression2> 2. Adopt a ternary operator built using new or existing keywords. The leading examples are: <condition> then <expression1> else <expression2> (if <condition>: <expression1> else: <expression2>) 3. Do nothing." Given the later addition of generator expressions with mandatory parentheses , the mandatory-parentheses version of a conditional expression looks less strange to me than it did then ;-). So I could happily use it even though I may still lean toward the other option 2 version (then-else) due to its not needing ':'s or a third elseif term for chaining. *If* you want general community input, I would suggest a runoff ballot with those four choices (and a summary of pros and cons of each), or fewer if you see any as unacceptible. Terry J. Reedy
-- --Guido van Rossum (home page: http://www.python.org/~guido/) _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/python-python-dev%40m.gman...
On 9/20/05, Terry Reedy
"Guido van Rossum"
wrote in message and +1 on adding a conditional expression. I believe (y if x else z) was my favorite last time, wasn't it?
No. That was your original proposal, which you later rejected.
Thanks for setting me straight; upon re-reading the PEP I couldn't even remember which one I favored at the time!
Your final 'favorite' was apparently (at the top)
"Proposal The proposed syntax is as follows: (if <condition>: <expression1> else: <expression2>) " (+ elif parts)
selected from
"Summary of the Current State of the Discussion Groups are falling into one of three camps: 1. Adopt a ternary operator built using punctuation characters: <condition> ? <expression1> : <expression2> 2. Adopt a ternary operator built using new or existing keywords. The leading examples are: <condition> then <expression1> else <expression2> (if <condition>: <expression1> else: <expression2>) 3. Do nothing."
Given the later addition of generator expressions with mandatory parentheses , the mandatory-parentheses version of a conditional expression looks less strange to me than it did then ;-). So I could happily use it even though I may still lean toward the other option 2 version (then-else) due to its not needing ':'s or a third elseif term for chaining.
I think I'd prefer (if <expr> then <expr> else <expre>) i.e. no colons. None of the other expression forms (list comprehensions and generator expressions) involving statement keywords use colons.
*If* you want general community input, I would suggest a runoff ballot with those four choices (and a summary of pros and cons of each), or fewer if you see any as unacceptible.
If there's one thing I've learned from the PEP 308 vote, it is that votes for language don't work. I prefer some discussion on Python-dev after which I pick one. -- --Guido van Rossum (home page: http://www.python.org/~guido/)
At 12:17 PM 9/20/2005 -0700, Guido van Rossum wrote:
I think I'd prefer (if <expr> then <expr> else <expre>) i.e. no colons. None of the other expression forms (list comprehensions and generator expressions) involving statement keywords use colons.
+1, despite the fact that we seem on a slippery slope towards becoming a kind of infix Lisp. ;) Between (yield x), (x for x in y), and now (if x then y else z), it seems that parentheses are all the rage now. Will we get (try <expr> finally <expr>) next? <0.5 wink>
*If* you want general community input, I would suggest a runoff ballot with those four choices (and a summary of pros and cons of each), or fewer if you see any as unacceptible.
If there's one thing I've learned from the PEP 308 vote, it is that votes for language don't work. I prefer some discussion on Python-dev after which I pick one.
Also +1. :)
On 9/20/05, Phillip J. Eby
At 12:17 PM 9/20/2005 -0700, Guido van Rossum wrote:
I think I'd prefer (if <expr> then <expr> else <expre>) i.e. no colons. None of the other expression forms (list comprehensions and generator expressions) involving statement keywords use colons.
+1, despite the fact that we seem on a slippery slope towards becoming a kind of infix Lisp. ;) Between (yield x), (x for x in y), and now (if x then y else z), it seems that parentheses are all the rage now. Will we get (try <expr> finally <expr>) next? <0.5 wink>
+1 from me as well. The use will be much more obvious to a newbie than ``<expr> ? <expr> : <expr>``. And I have used the syntactic-heavy listcomps in Haskell and I must say that Python's version is much nicer. I like the wordy version. =)
*If* you want general community input, I would suggest a runoff ballot with those four choices (and a summary of pros and cons of each), or fewer if you see any as unacceptible.
If there's one thing I've learned from the PEP 308 vote, it is that votes for language don't work. I prefer some discussion on Python-dev after which I pick one.
Also +1. :)
+1 from me, although I sure got lambasted by some people when I said I liked this style during the whole decorator debate. =) -Brett
Guido van Rossum wrote:
I think I'd prefer (if <expr> then <expr> else <expre>) i.e. no colons. None of the other expression forms (list comprehensions and generator expressions) involving statement keywords use colons.
FWIW, I find this quite intuitive. It follows the same pattern as LCs and GEs -- remove the colons and add parentheses (or brackets for LCs). So I'm +1. STeVe -- You can wordify anything if you just verb it. --- Bucky Katt, Get Fuzzy
Steven Bethard wrote:
Guido van Rossum wrote:
I think I'd prefer (if <expr> then <expr> else <expre>) i.e. no colons. None of the other expression forms (list comprehensions and generator expressions) involving statement keywords use colons.
FWIW, I find this quite intuitive. It follows the same pattern as LCs and GEs -- remove the colons and add parentheses (or brackets for LCs). So I'm +1.
*But*, in LC's and GE's, the body of the main clause of the statement is also pulled out and placed in front of the keyword: def gen(): for VAR in ITERABLE: if COND: yield EXPR becomes: gen = (EXPR for VAR in ITERABLE if COND) This makes sense to me, because the most important thing in the generator expression is the way each element is populated - the source iterable and the filtering condition do matter, but they aren't as important. It also makes the expression forms more declarative in nature, rather than being procedural statements embedded inside an expression. Notice also that, in this case, if ITERABLE is empty, or COND always evaluates false in boolean context, then EXPR is never executed - in other words, Python already has precedent for out of order code execution in expression evaluation. Guido's original PEP 308 proposal worked much the same way: if COND: x = EXPR1 else: x = EXPR2 became: x = (EXPR1 if COND else EXPR2) I see this as similar in spirit to the current form of LC's and GE's - the most important things are the two possible values rather than the condition for choosing between them, and this form makes them clearly visible at the start and end of the expression, rather than embedding one of them in the middle. The post-filtered form is also similarly declarative rather than procedural. This version doesn't need a separate 'elif' form - elif can be written as: x = (EXPR1 if COND1 else EXPR2 if COND2 else EXPR3) Note that the keyword count is no higher than if 'elif' was used, because the 'then' keyword isn't needed: x = (if COND1 then EXPR1 elif COND2 then EXPR2 else EXPR3) Here's Raymond's problematic example using this original PEP 308 form: def real(self): 'Return a vector with the real part of each input element' # do not convert integer inputs to floats return self.map(lambda z: (z.real if type(z)==types.ComplexType else z)) And the other non-colon, keyword based proposal in PEP 308's top four: def real(self): 'Return a vector with the real part of each input element' # do not convert integer inputs to floats return self.map(lambda z: (if type(z)==types.ComplexType then z.real else z)) Another common use case would be for mutable default arguments: x = ([] if arg is None else list(arg)) x = (if arg is None then [] else list(arg)) Basically, I'm +1 on the original PEP 308 form because it reads more naturally (and more like LC's and GE's) to me in expression contexts, and +0 on the "if/then/elif/else" form (because I would like a real conditional operator). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia --------------------------------------------------------------- http://boredomandlaziness.blogspot.com
On 9/20/05, Nick Coghlan
Basically, I'm +1 on the original PEP 308 form because it reads more naturally (and more like LC's and GE's) to me in expression contexts, and +0 on the "if/then/elif/else" form (because I would like a real conditional operator).
I agree that (expr if cond else expr) fits far more naturally these days given the ordering of generator expressions (and list comprehensions, but they were around when PEP 308 was discussed, so I don't think they work as well as evidence :-)) Also, (expr if cond else expr) doesn't naturally admit an elif case, reducing complexity (and the tendency to overuse the construct in complex ways) a little. And it doesn't need a new keyword. I have a vague fondness for this form. I really can't express it very well, but the if-then-else version just feels a little too "boring and conventional". I'm sure people will get used to it (heck, we've got decorators and print >> :-)) but maybe pushing a (mildly) idiosyncratic form isn't worth opening that can of worms again. I'm +1 on a conditiona expression. I suspect the time is now right. I'm +1 on *one* of (expr if cond else expr) or (if cond then expr else expr) With the latter, I don't mind if elif is added or not. I'm +1000000000 on Guido just making the decision. No more votes, please! Paul.
On Wed, Sep 21, 2005, Nick Coghlan wrote:
Steven Bethard wrote:
Guido van Rossum wrote:
I think I'd prefer (if <expr> then <expr> else <expre>) i.e. no colons. None of the other expression forms (list comprehensions and generator expressions) involving statement keywords use colons.
FWIW, I find this quite intuitive. It follows the same pattern as LCs and GEs -- remove the colons and add parentheses (or brackets for LCs). So I'm +1.
*But*, in LC's and GE's, the body of the main clause of the statement is also pulled out and placed in front of the keyword:
def gen(): for VAR in ITERABLE: if COND: yield EXPR
becomes:
gen = (EXPR for VAR in ITERABLE if COND)
This makes sense to me, because the most important thing in the generator expression is the way each element is populated - the source iterable and the filtering condition do matter, but they aren't as important.
Yes, and when the looping becomes the focal point, one should generally rewrite a listcomp as a for loop. Nevertheless, because boolean expressions have non-boolean semantics in Python (i.e. they return the objects rather than a boolean value), conditional expressions will almost certainly have the condition as the focal point because a simple boolean expression is no longer sufficient. I am therefore strongly opposed to the "a if cond else b" form. (We've already agreed that Raymond's proposal to make boolean expressions return booleans is dead, right?) I'm also opposed to elif in conditional expressions -- let's keep this a simple Pythonic rewrite of C's ternary. I'm +0 on requiring parentheses precisely because they're annoying. I'm still expecting simple boolean expressions to be the primary use case, and my hunch is that overall Python code will read better with the ternary looking cluttered. -- Aahz (aahz@pythoncraft.com) <*> http://www.pythoncraft.com/ The way to build large Python applications is to componentize and loosely-couple the hell out of everything.
[Aahz]
I'm also opposed to elif in conditional expressions -- let's keep this a simple Pythonic rewrite of C's ternary.
I'm +0 on requiring parentheses precisely because they're annoying. I'm still expecting simple boolean expressions to be the primary use case, and my hunch is that overall Python code will read better with the ternary looking cluttered.
FWIW, I scanned the standard library for all the and/or pairings where a conditional expression was applicable. This sampling can serve as a reference for what "typical" uses would look like in real Python code as created by a number of different authors. It only takes about five minutes to try out a given syntax proposal on all the fragments listed below. That short exercise provides an excellent insight into the look and feel of each proposal in real world code. Raymond --------------------------------------------------------------------- cgitb.py: file = file and os.path.abspath(file) or '?' cgitb.py: formatter = (self.format=="html") and html or text compileal1.py: cfile = fullname + (__debug__ and 'c' or 'o') csv.py: (quotes[a] > quotes[b]) and a or b, quotes.keys()) csv.py: (delims[a] > delims[b]) and a or b, delims.keys()) csv.py: modes[char] = reduce(lambda a, b: a[1] > b[1] and a or b, DocXMLRPCServer.py: anchor = (cl and cl.__name__ or '') + '-' + name fileinput.py: isfirstline() and "*" or "", line) formatter.py: self.writer.send_paragraph((blankline and 1) or 0) gettext.py: __builtin__.__dict__['_'] = unicode and self.ugettext or self.gettext imaplib.py: l = map(lambda x:'%s: "%s"' % (x[0], x[1][0] and '" "'.join(x[1]) or ''), l) imputil.py: _suffix_char = __debug__ and 'c' or 'o' keyword.py: iptfile = args and args[0] or "Python/graminit.c" pickle.py: self.write(obj and NEWTRUE or NEWFALSE) pickle.py: self.write(obj and TRUE or FALSE) pickletools.py: pos is None and "<unknown>" or pos, py_compile.py: cfile = file + (__debug__ and 'c' or 'o') pydoc.py: return result and re.sub('^ *\n', '', rstrip(result)) or '' pydoc.py: anchor = (cl and cl.__name__ or '') + '-' + name pydoc.py: lhs = name and '<strong>%s</strong> = ' % name or '' pydoc.py: contents = doc and [doc + '\n'] or [] pydoc.py: line = (name and name + ' = ' or '') + repr pydoc.py: line = (name and self.bold(name) + ' = ' or '') + repr pydoc.py: host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost' pydoc.py: font = ('helvetica', sys.platform == 'win32' and 8 or 10) robotp~1.py: return (self.allowance and "Allow" or "Disallow")+": "+self.path telnet~1.py: cmd == DO and 'DO' or 'DONT', ord(opt)) telnet~1.py: cmd == WILL and 'WILL' or 'WONT', ord(opt)) thread~1.py: n!=1 and "s" or "") token.py: inFileName = args and args[0] or "Include/token.h" tokenize.py: yield (parenlev > 0 and NL or NEWLINE, unittest.py: return doc and doc.split("\n")[0].strip() or None unittest.py: return doc and doc.split("\n")[0].strip() or None unittest.py: (run, run != 1 and "s" or "", timeTaken)) urllib.py: safe_map[c] = (c in safe) and c or ('%%%02X' % i) urllib2.py: type = file and 'I' or 'D' xdrlib.py: print pred(x) and 'succeeded' or 'failed', ':', x xmlrpclib.py: write(value and "1" or "0")
On 9/29/05, Raymond Hettinger
FWIW, I scanned the standard library for all the and/or pairings where a conditional expression was applicable. This sampling can serve as a reference for what "typical" uses would look like in real Python code as created by a number of different authors.
It only takes about five minutes to try out a given syntax proposal on all the fragments listed below. That short exercise provides an excellent insight into the look and feel of each proposal in real world code.
I did this for my favorite proposal, and ended up with the list shown further down below. I think they all looks great! The only problem is that it's not easy to come up with a regex-based way to transform C and X or Y into X if C else Y because it's hard to determine where C starts. So I recommend that people leave existing and/or code alone but start writing if/else expressions in new code only. After all there's nothing wrong with and/or. cgitb.py: file = os.path.abspath(file) if file else '?' cgitb.py: formatter = html if self.format == "html" else text compileal1.py: cfile = fullname + ('c' if __debug__ else 'o') csv.py: a if (quotes[a] > quotes[b]) else b, quotes.keys()) csv.py: a if (delims[a] > delims[b]) else b, delims.keys()) csv.py: modes[char] = reduce(lambda a, b: a if a[1] > b[1] else b, DocXMLRPCServer.py: anchor = (cl.__name__ if cl else '') + '-' + name fileinput.py: "*" if isfirstline() else "", line) formatter.py: self.writer.send_paragraph((1) if blankline else 0) gettext.py: __builtin__.__dict__['_'] = self.ugettext if unicode else self.gettext imaplib.py: l = map(lambda x:'%s: "%s"' % (x[0], '" "'.join(x[1]) if x[1][0] else ''), l) imputil.py: _suffix_char = 'c' if __debug__ else 'o' keyword.py: iptfile = args[0] if args else "Python/graminit.c" pickle.py: self.write(NEWTRUE if obj else NEWFALSE) pickle.py: self.write(TRUE if obj else FALSE) pickletools.py: "<unknown>" if pos is None else pos, py_compile.py: cfile = file + ('c' if __debug__ else 'o') pydoc.py: return re.sub('^ *\n', '', rstrip(result)) if result else '' pydoc.py: anchor = (cl.__name__ if cl else '') + '-' + name pydoc.py: lhs = '<strong>%s</strong> = ' % name if name else '' pydoc.py: contents = [doc + '\n'] if doc else [] pydoc.py: line = (name + ' = ' if name else '') + repr pydoc.py: line = (self.bold(name) + ' = ' if name else '') + repr pydoc.py: host = '127.0.0.1' if (sys.platform == 'mac') else 'localhost' pydoc.py: font = ('helvetica', 8 if sys.platform == 'win32' else 10) robotp~1.py: return (self."Allow" if allowance else "Disallow")+": "+self.path telnet~1.py: 'DO' if cmd == DO else 'DONT', ord(opt)) telnet~1.py: 'WILL' if cmd == WILL else 'WONT', ord(opt)) thread~1.py: "s" if n!=1 else "") token.py: inFileName = args[0] if args else "Include/token.h" tokenize.py: yield (parenlev > NL if 0 else NEWLINE, unittest.py: return doc.split("\n")[0].strip() if doc else None unittest.py: return doc.split("\n")[0].strip() if doc else None unittest.py: (run, run != "s" if 1 else "", timeTaken)) urllib.py: safe_map[c] = c if (c in safe) else ('%%%02X' % i) urllib2.py: type = 'I' if file else 'D' xdrlib.py: print 'succeed' if pred(x) else 'failed', ':', x xmlrpclib.py: write("1" if value else "0") -- --Guido van Rossum (home page: http://www.python.org/~guido/)
On 9/29/05, Guido van Rossum
The only problem is that it's not easy to come up with a regex-based way to transform
C and X or Y
into
X if C else Y
(my 2 cents) I find this proposal very confusing. The order is not logical at all. One usually expects to find the condition on one side, and the alternatives on another side (this is how it's done in every conditional construct I know of : traditional if-then-else, lisp's cond, switch statements...). But there the condition is in the middle, which breaks the natural reading order and feels obfuscated. This is especially true if the "X" in "X if C else Y" happens to be a non-trivial expression - witness your example from unittest.py: return doc.split("\n")[0].strip() if doc else None ... because then the condition (which is the most important part of the statement) is shadowed by the complexity of the first alternative; and the two alternatives, which should logically be siblings, are separated by something which has a different role in the construct. This is exactly like a switch/case statement where the "switch" would have to be inserted in the middle of two "case"'s. Also, generally, one of the most annoying things in computer languages is when they try to invent their own unnatural conditional forms: such as Perl's inverted forms or "unless" statement. Regards Antoine.
Antoine Pitrou wrote:
This is especially true if the "X" in "X if C else Y" happens to be a non-trivial expression - witness your example from unittest.py: return doc.split("\n")[0].strip() if doc else None
... because then the condition (which is the most important part of the statement) is shadowed by the complexity of the first alternative; and the two alternatives, which should logically be siblings, are separated by something which has a different role in the construct.
I think the perception of what's important is relevant here - to me, the behaviour in the normal case (i.e., non-empty doc) is the most important element. The conditional, and the default value returned when 'doc' is empty are interesting, but are a corner case, rather than a fundamental element of the function's behaviour.
This is exactly like a switch/case statement where the "switch" would have to be inserted in the middle of two "case"'s.
Well, no - because it is possible to consider an if-else as a parameterised binary operation that chooses between the left and right operands (i.e., it's like an "or", only we're asking that the decision be made based on something other than the truth value of the left hand operand). That is, in the case where the left hand expression has no side effects, the following pairs of expression are essentially equivalent: a or b <-> a if a else b a and b <-> a if not a else b In the switch statement example, the switch statement is inherently an n-ary operation, so there is no comparable way of finding a spot to put the switch variable "in the middle".
Also, generally, one of the most annoying things in computer languages is when they try to invent their own unnatural conditional forms: such as Perl's inverted forms or "unless" statement.
Even more annoying are constructs that don't gel with the rest of the language, though. Regards, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia --------------------------------------------------------------- http://boredomandlaziness.blogspot.com
Nick Coghlan wrote:
i.e., it's like an "or", only we're asking that the decision be made based on something other than the truth value of the left hand operand.
Hmmm, then maybe it should be a or c if b or perhaps a or, if b, c :-) -- Greg Ewing, Computer Science Dept, +--------------------------------------+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | greg.ewing@canterbury.ac.nz +--------------------------------------+
Antoine Pitrou wrote:
The only problem is that it's not easy to come up with a regex-based way to transform
C and X or Y
into
X if C else Y
One way is to parse it manually to a list. This was just a test, but more samples can be added friarly easy. samples = [ # start, cond, x, y, end ("cgitb.py: file =", "file", "os.path.abspath(file)", "'?'", ""), ("cgitb.py: formatter =", '(self.format=="html")', "html", "text", ""), ("compileal1.py: cfile = fullname + (", "__debug__","'c'","'o'",")"), ] for s,c,x,y,e in samples: print "%s %s and %s or %s %s" % (s,c,x,y,e) print "%s %s if %s else %s %s" % (s,x,c,y,e) print "%s (if %s then %s else %s) %s" % (s,c,x,y,e) print "%s (%s ? %s : %s) %s" % (s,c,x,y,e) print
(my 2 cents)
I find this proposal very confusing. The order is not logical at all. One usually expects to find the condition on one side, and the alternatives on another side (this is how it's done in every conditional construct I know of : traditional if-then-else, lisp's cond, switch statements...). But there the condition is in the middle, which breaks the natural reading order and feels obfuscated.
I found that my preference depends on the situation. I like (if cond then expr1 else expr2) for most things because having the condition in front tells me the purpose, And it's better represents the order the terms are evaluated in. But when checking a value and either changing it or leaving it alone, I tended to want to type it as. value = (value if cond else alternate_value) In this case the condition is an accept or reject for the alternate_value. And since the first term is a simple name instead of a complex expression, the order of evaluation doesn't bother me. Personally I prefer the function form best for the pure simplicity of it, if(cond, e1, e2), but of course that doesn't do the shortcut behavior and it pre-evaluates the arguments, so it's not an answer. Cheers, Ron
Guido> After all there's nothing wrong with and/or. Especially if it's correct. <wink> Skip
Guido van Rossum wrote:
On 9/29/05, Raymond Hettinger
wrote: FWIW, I scanned the standard library for all the and/or pairings where a conditional expression was applicable. This sampling can serve as a reference for what "typical" uses would look like in real Python code as created by a number of different authors.
It only takes about five minutes to try out a given syntax proposal on all the fragments listed below. That short exercise provides an excellent insight into the look and feel of each proposal in real world code.
I did this for my favorite proposal, and ended up with the list shown further down below.
I think they all looks great!
The fact that so few were found in whole of the standard library does put the use case into question, though, no? Though I am sure more could be found with a more thorough scan.
The only problem is that it's not easy to come up with a regex-based way to transform
C and X or Y
into
X if C else Y
because it's hard to determine where C starts. So I recommend that people leave existing and/or code alone but start writing if/else expressions in new code only. After all there's nothing wrong with and/or.
cgitb.py: file = os.path.abspath(file) if file else '?' cgitb.py: formatter = html if self.format == "html" else text compileal1.py: cfile = fullname + ('c' if __debug__ else 'o') csv.py: a if (quotes[a] > quotes[b]) else b, quotes.keys()) csv.py: a if (delims[a] > delims[b]) else b, delims.keys()) csv.py: modes[char] = reduce(lambda a, b: a if a[1] > b[1] else b, DocXMLRPCServer.py: anchor = (cl.__name__ if cl else '') + '-' + name fileinput.py: "*" if isfirstline() else "", line) formatter.py: self.writer.send_paragraph((1) if blankline else 0) gettext.py: __builtin__.__dict__['_'] = self.ugettext if unicode else self.gettext imaplib.py: l = map(lambda x:'%s: "%s"' % (x[0], '" "'.join(x[1]) if x[1][0] else ''), l) imputil.py: _suffix_char = 'c' if __debug__ else 'o' keyword.py: iptfile = args[0] if args else "Python/graminit.c" pickle.py: self.write(NEWTRUE if obj else NEWFALSE) pickle.py: self.write(TRUE if obj else FALSE) pickletools.py: "<unknown>" if pos is None else pos, py_compile.py: cfile = file + ('c' if __debug__ else 'o') pydoc.py: return re.sub('^ *\n', '', rstrip(result)) if result else '' pydoc.py: anchor = (cl.__name__ if cl else '') + '-' + name pydoc.py: lhs = '<strong>%s</strong> = ' % name if name else '' pydoc.py: contents = [doc + '\n'] if doc else [] pydoc.py: line = (name + ' = ' if name else '') + repr pydoc.py: line = (self.bold(name) + ' = ' if name else '') + repr pydoc.py: host = '127.0.0.1' if (sys.platform == 'mac') else 'localhost' pydoc.py: font = ('helvetica', 8 if sys.platform == 'win32' else 10) robotp~1.py: return (self."Allow" if allowance else "Disallow")+": "+self.path telnet~1.py: 'DO' if cmd == DO else 'DONT', ord(opt)) telnet~1.py: 'WILL' if cmd == WILL else 'WONT', ord(opt)) thread~1.py: "s" if n!=1 else "") token.py: inFileName = args[0] if args else "Include/token.h" tokenize.py: yield (parenlev > NL if 0 else NEWLINE, unittest.py: return doc.split("\n")[0].strip() if doc else None unittest.py: return doc.split("\n")[0].strip() if doc else None unittest.py: (run, run != "s" if 1 else "", timeTaken)) urllib.py: safe_map[c] = c if (c in safe) else ('%%%02X' % i) urllib2.py: type = 'I' if file else 'D' xdrlib.py: print 'succeed' if pred(x) else 'failed', ':', x xmlrpclib.py: write("1" if value else "0")
Having though about it more closely, the reason I believe it might confuse newbies is because until the "else" comes along the construct can easily be read as a statement with a conditional suffix, and it's only after you read the "else" it becomes obvious that it's the expression that's conditional. I realise that this reading will become habitual once this proposal is put into the language, but I do think this will be a source of confusion to newcomers (who should anyway be steered away from all the magic of ternary expressions, list comprehensions, generator expressions and the like. I would argue for mandatory parentheses around the expression, leaving room later (probably after Guido is no longer around to be sick at the site of it) for: def f(condition): return something if condition # no else! return somethingElse not-expecting-this-to-fly-ly y'rs - steve -- Steve Holden +44 150 684 7255 +1 800 494 3119 Holden Web LLC www.holdenweb.com PyCon TX 2006 www.pycon.org
On 9/29/05, Steve Holden
I would argue for mandatory parentheses around the expression, leaving room later (probably after Guido is no longer around to be sick at the site of it) for:
def f(condition): return something if condition # no else! return somethingElse
not-expecting-this-to-fly-ly y'rs - steve
Let me give you what you expect. If all the "X if C else Y" syntax does is prevent that atrocity from ever being introduced, it would be worth it. :) -- --Guido van Rossum (home page: http://www.python.org/~guido/)
Guido van Rossum wrote:
On 9/29/05, Steve Holden
wrote: I would argue for mandatory parentheses around the expression, leaving room later (probably after Guido is no longer around to be sick at the site of it) for:
def f(condition): return something if condition # no else! return somethingElse
not-expecting-this-to-fly-ly y'rs - steve
Let me give you what you expect. If all the "X if C else Y" syntax does is prevent that atrocity from ever being introduced, it would be worth it. :)
Well, fine. However, it does allow atrocities like func(f for f in lst if f > -1 if f < 0 else +1) I realise that any chosen syntax is subject to abuse, but a conditional expression in a (currently allowed) conditional context will be guaranteed obscure. Your original instinct to omit conditional expressions was right! far-too-late-ly y'rs - steve -- Steve Holden +44 150 684 7255 +1 800 494 3119 Holden Web LLC www.holdenweb.com PyCon TX 2006 www.python.org/pycon/
[Guido]
Let me give you what you expect. If all the "X if C else Y" syntax does is prevent that atrocity from ever being introduced, it would be worth it. :)
[Steve]
Well, fine. However, it does allow atrocities like
func(f for f in lst if f > -1 if f < 0 else +1)
No it doesn't! Inside an 'if' (of any flavor), further ifs have to be nested. So you'd have to write func(f for f in lst if f > (-1 if f < 0 else +1)) or perhaps func(f for f in lst if (f > -1 if f < 0 else +1)) But I doubt you meant to write +1 where True could have sufficed. :) An if-else expression has lower priority than anything else except lambda; the expression lambda x: x if x >= 0 else -x is equivalent to lambda x: (x if x >= 0 else -x)
I realise that any chosen syntax is subject to abuse, but a conditional expression in a (currently allowed) conditional context will be guaranteed obscure. Your original instinct to omit conditional expressions was right!
Now you've pushed me over the edge. I've made up my mind now, "X if C else Y" it will be. I hope to find time to implement it in Python 2.5. Let it be as controversial as bool or @decorator, I don't care. -- --Guido van Rossum (home page: http://www.python.org/~guido/)
Guido van Rossum wrote:
[Guido]
Let me give you what you expect. If all the "X if C else Y" syntax does is prevent that atrocity from ever being introduced, it would be worth it. :)
[Steve]
Well, fine. However, it does allow atrocities like
func(f for f in lst if f > -1 if f < 0 else +1)
No it doesn't! Inside an 'if' (of any flavor), further ifs have to be nested. So you'd have to write
func(f for f in lst if f > (-1 if f < 0 else +1))
or perhaps
func(f for f in lst if (f > -1 if f < 0 else +1))
But I doubt you meant to write +1 where True could have sufficed. :)
:) All that said, inside an "if" is hardly the best place for a conditional of any kind. Clearly such usage can go down as abuse.
An if-else expression has lower priority than anything else except lambda; the expression
lambda x: x if x >= 0 else -x
is equivalent to
lambda x: (x if x >= 0 else -x)
That's about the only way it would make sense, I suppose.
I realise that any chosen syntax is subject to abuse, but a conditional expression in a (currently allowed) conditional context will be guaranteed obscure. Your original instinct to omit conditional expressions was right!
Now you've pushed me over the edge. I've made up my mind now, "X if C else Y" it will be. I hope to find time to implement it in Python 2.5. Let it be as controversial as bool or @decorator, I don't care.
Not before time, either. If this ends the discussion then I'll consider I've done everyone a favour. Sometimes no decision is worse than the wrong decision ;-). regards Steve -- Steve Holden +44 150 684 7255 +1 800 494 3119 Holden Web LLC www.holdenweb.com PyCon TX 2006 www.python.org/pycon/
I did this for my favorite proposal, and ended up with the list shown further down below.
I think they all looks great!
The fact that so few were found in whole of the standard library does put the use case into question, though, no? Though I am sure more could be found with a more thorough scan.
There's lots of code in it that looks like this: def __init__(self, foo = None): if foo is not None: self.foo = foo else: self.foo = self.getFooDefault() With if/else it can be written: def __init__(self, foo = None): self.foo = foo if foo is not None else self.getFooDefault() However, I'm convinced that the latter version is less readable than the former. Often the line becomes more than 80 characters so there's no gain in translating it to an if-else expression because you would still have to split the line, other times the condition is so complex that it deserves its own line. Many opportunities for uses, but atleast as many for abuses. -- mvh Björn
It only takes about five minutes to try out a given syntax proposal on all the fragments listed below. That short exercise provides an excellent insight into the look and feel of each proposal in real world code.
I did this for my favorite proposal, and ended up with the list shown further down below.
I think they all looks great!
They mostly look great to me too :-) The exceptions are the ones in pydoc which have an odd feel to them and, to my eyes, don't parse well. I can't put my finger on the issue -- it could be that any ternary operator syntax breaks down when used in series with other operators or when there are complex sub-expressions.
pydoc.py: return re.sub('^ *\n', '', rstrip(result)) if result else '' pydoc.py: anchor = (cl.__name__ if cl else '') + '-' + name pydoc.py: lhs = '<strong>%s</strong> = ' % name if name else '' pydoc.py: contents = [doc + '\n'] if doc else [] pydoc.py: line = (name + ' = ' if name else '') + repr pydoc.py: line = (self.bold(name) + ' = ' if name else '') + repr pydoc.py: host = '127.0.0.1' if (sys.platform == 'mac') else 'localhost' pydoc.py: font = ('helvetica', 8 if sys.platform == 'win32' else 10)
There is one that looks like it could be completely mis-interpreted: (name + ' = ' if name else '') # as written above ((name + ' = ') if name else '') # one mental interpretation (name + (' = ' if name else '')) # an incorrect interpretation The grouping issue doesn't arise for syntaxes that start with a keyword: (if name then name + ' = ' else '') but even those suffer from unclear precedence when used with binary operations on the right: (if cond then a else b + c). Raymond
Guido van Rossum wrote:
I did this for my favorite proposal, and ended up with the list shown further down below.
I think they all looks great!
I'm sorry for my bad English IMHO, if condition is nontrivial, then the syntax: expr1 if some complex condition else expr2 can be more hard to read as compared with: if some complex condition then expr1 else expr2 In the second form visual comparison of expr1 and expr2 is simpler because its adjacent placement. For example, in expression 'DO' if cmd == DO and flag == OK or x is None else 'DONT' 'DO' and 'DONT' visually divided and eyes must move there and back for find the difference between them. As opposite, in expression if cmd == DO and flag == OK or x is None then 'DO' else 'DONT' it is very easy to determine what is possible expression output. It is a bit more readable from my point of view Best regards, Alexander mailto:kozlovsky@mail.spbnit.ru
"Guido van Rossum"
After all there's nothing wrong with and/or.
This is one reason 'no addition' got a relatively high rank in the vote. Examples...
telnet~1.py: 'DO' if cmd == DO else 'DONT', versus cmd == DO and 'DO' or 'DONT'
I still stronly prefer this order and even slightly prefer this form. I might even prefer a complete inversion of the order: x else y if c 'DO' else 'DONT' if cmd != DO except that that does not chain at all well. Terry J. Reedy
Raymond Hettinger wrote:
[Aahz]
I'm also opposed to elif in conditional expressions -- let's keep this
a
simple Pythonic rewrite of C's ternary.
I'm +0 on requiring parentheses precisely because they're annoying.
I'm
still expecting simple boolean expressions to be the primary use case, and my hunch is that overall Python code will read better with the ternary looking cluttered.
FWIW, I scanned the standard library for all the and/or pairings where a conditional expression was applicable. This sampling can serve as a reference for what "typical" uses would look like in real Python code as created by a number of different authors.
Thanks for digging those out - I was thinking that would be a useful exercise, but hadn't taken the time to think of an easy way to find relevant lines.
It only takes about five minutes to try out a given syntax proposal on all the fragments listed below. That short exercise provides an excellent insight into the look and feel of each proposal in real world code.
I tried it with (if C then A else B) and (A if C else B), and found both to be significantly more readable than the current code. In particular, I wouldn't want to bet money that none of the examples are buggy, as there were a few cases where the "A" value could conceivably be 0 or '', but I couldn't tell if it was possible for the condition to also be true in those cases. Comparing the two syntaxes I tried, I found that the infix notation generally required the addition of parentheses around the "A" expression when that expression was itself a binary operation - otherwise the precedence was unclear and, even with parentheses around the whole conditional, the layout gave the impression that the conditional expression only applied to the second argument to the binary operation in "A". That said, the more verbose form still felt like it had the elements out of sequence - it was just crying out for the expression to be rewritten as a statement. Regards, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia --------------------------------------------------------------- http://boredomandlaziness.blogspot.com
"Guido van Rossum"
On 9/20/05, Terry Reedy
wrote: Given the later addition of generator expressions with mandatory parentheses , the mandatory-parentheses version of a conditional expression looks less strange to me than it did then ;-). So I could happily use it even though I may still lean toward the other option 2 version (then-else) due to its not needing ':'s or a third elseif term for chaining.
I think I'd prefer (if <expr> then <expr> else <expre>) i.e. no colons. None of the other expression forms (list comprehensions and generator expressions) involving statement keywords use colons.
I presume this revision would continue to include elif clauses. If I put on a 'designing Python for everyone' hat, then the presence of the leading 'if' looks better than the slightly-too-cute (especially for Python) abbreviated version. +1
*If* you want general community input, I would suggest a runoff ballot with those four choices (and a summary of pros and cons of each), or fewer if you see any as unacceptible.
If there's one thing I've learned from the PEP 308 vote, it is that votes for language don't work. I prefer some discussion on Python-dev after which I pick one.
If we reject both the status quo and the symbol-tax form and agree on the above as the best wordy form, then it is a moot point anyway ;-) C.l.p. newcomers continue to periodically request "How do I write conditional expressions?". I think most will be happier with something clear and readable. Terry J. Reedy
Guido van Rossum wrote:
I think I'd prefer (if <expr> then <expr> else <expre>) i.e. no colons. None of the other expression forms (list comprehensions and generator expressions) involving statement keywords use colons.
While I like the looks of the form without colons better, I can't quite follow this argument for it. In LCs and GEs, colons wouldn't make any sense in the first place because the expression controlled by "for" and "if" is written before it: [expression(x) for x in y]. Just where would anyone put a colon there, anyway? A colon does make sense if something follows it, as is currently the case in lambda expressions. It would also be the case in an (if x: y else: z) form. I have a feeling that trying to make all expression forms which happen to use statement keywords colon-free is seeking an artificial consistency. I'm happy to be proven wrong, though. +1 on the idea of introducing a conditional expression in the first place, though. -- Thomas
I think I'd prefer (if <expr> then <expr> else <expre>) i.e. no colons. None of the other expression forms (list comprehensions and generator expressions) involving statement keywords use colons.
FWLIW, this was my (strong) preference back at the time of the original discussion. -- g
Guido van Rossum
Given the later addition of generator expressions with mandatory parentheses , the mandatory-parentheses version of a conditional expression looks less strange to me than it did then ;-). So I could happily use it even though I may still lean toward the other option 2 version (then-else) due to its not needing ':'s or a third elseif term for chaining.
I think I'd prefer (if <expr> then <expr> else <expre>) i.e. no colons.
My problem with this syntax is that it can be hard to read: return if self.arg is None then default else self.arg looks worryingly like return NAME NAME.NAME NAME NAME NAME NAME NAME NAME.NAME to me.
None of the other expression forms (list comprehensions and generator expressions) involving statement keywords use colons.
This is also true.
*If* you want general community input, I would suggest a runoff ballot with those four choices (and a summary of pros and cons of each), or fewer if you see any as unacceptible.
If there's one thing I've learned from the PEP 308 vote, it is that votes for language don't work. I prefer some discussion on Python-dev after which I pick one.
Well, this is my input (and now I'm going to try and stay out of it). Cheers, mwh -- 59. In English every word can be verbed. Would that it were so in our programming languages. -- Alan Perlis, http://www.cs.yale.edu/homes/perlis-alan/quotes.html
On Wed, 2005-09-21 at 11:10, Michael Hudson wrote:
My problem with this syntax is that it can be hard to read:
return if self.arg is None then default else self.arg
looks worryingly like
return NAME NAME.NAME NAME NAME NAME NAME NAME NAME.NAME
to me.
I think that requriing parens helps a lot with the list-of-names problem - it nicely delimits the conditional expression for human readers: return (if self.arg is None then default else self.arg) In particular it breaks up the misleading grouping "return if". Mark Russell
Michael Hudson wrote:
Guido van Rossum
writes: Given the later addition of generator expressions with mandatory parentheses , the mandatory-parentheses version of a conditional expression looks less strange to me than it did then ;-). So I could happily use it even though I may still lean toward the other option 2 version (then-else) due to its not needing ':'s or a third elseif term for chaining.
I think I'd prefer (if <expr> then <expr> else <expre>) i.e. no colons.
My problem with this syntax is that it can be hard to read:
return if self.arg is None then default else self.arg
looks worryingly like
return NAME NAME.NAME NAME NAME NAME NAME NAME NAME.NAME
to me.
But that's exactly what any language looks like if you get abstract enough: WORD WORD WORD WORD WORD WORD WORD And in fact, one read and understands your return statement just like an English sentence -- word by word from beginning to end. This seems an argument FOR the syntax not against. Moreover, if one uses the proposed parenthesized syntax, even the slightly odd word order of "return if" is mitigated. return (if self.arg is None then default else self.arg)
None of the other expression forms (list comprehensions and generator expressions) involving statement keywords use colons.
This is also true.
*If* you want general community input, I would suggest a runoff ballot with those four choices (and a summary of pros and cons of each), or fewer if you see any as unacceptible.
If there's one thing I've learned from the PEP 308 vote, it is that votes for language don't work. I prefer some discussion on Python-dev after which I pick one.
Well, this is my input (and now I'm going to try and stay out of it).
Cheers, mwh
Gary Herron wrote:
And in fact, one read and understands your return statement just like an English sentence -- word by word from beginning to end. This seems an argument FOR the syntax not against. Moreover, if one uses the proposed parenthesized syntax, even the slightly odd word order of "return if" is mitigated.
The reason I like "a if b else c" is because it has the most natural word order. In English, My dog is happy if he has a bone, else sad. sounds much more natural than My dog is, if he has a bone, happy, else sad. In return statements, return self.arg if self.arg is not None else default looks quite all right to me. I think the fact that it does resemble English word order so much prevents the word-soup problem from occurring. Interestingly, it looks *more* odd to me if parens are included: return (self.arg if self.arg is not None else default) I think this is because, without the parens, I tend to read the "if" as applying to the whole phrase "return self.arg", not just to the "self.arg". The English analogy is rewriting "My dog is happy if he has a bone" as "If he has a bone, my dog is happy", which also sounds natural, whereas "My dog is, if he has a bone, happy" sounds unnatural. So I still prefer "a if b else c" to any of the alternatives, and I still think parens should not be required. -- Greg Ewing, Computer Science Dept, +--------------------------------------+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | greg.ewing@canterbury.ac.nz +--------------------------------------+
The reason I like "a if b else c" is because it has the most natural word order. In English, My dog is happy if he has a bone, else sad. sounds much more natural than My dog is, if he has a bone, happy, else sad.
Neither sounds very natural to me; conditional expressions don't occur much in English. It's much more common to hear something like My dog is happy if he has a bone; otherwise he's sad. And that would correspond to a postfix conditional operator on *statements*, not expressions; Perl and Ruby have this, but it doesn't seem very Pythonic.
Interestingly, it looks *more* odd to me if parens are included:
return (self.arg if self.arg is not None else default)
I think this is because, without the parens, I tend to read the "if" as applying to the whole phrase "return self.arg", not just to the "self.arg".
Which is one reason why I *don't* like the proposed "consequent if antecedent else alternative" syntax; it looks like a statement modifier when it isn't really one. When you're forced (by the parens) to read it correctly, you stop liking it! :-) * Conditional expressions do occur in English, though, and they do generally have the consequent at the front. But ... they also generally have the "else-marker" right at the end. "Buy some pork if it's going cheap, and some beef if not." "You can divide an angle into N equal parts with ruler and compasses if N is a power of 2 times a product of distinct Fermat primes, but not if N has any other form." "I sleep all night and work all day." I don't think a syntax that authentically mirrors the structure of conditional expressions in English is likely to be very good. x = (123 if p==q; 321 otherwise) x = (123 if p==q, else 321 if not) x = (123 if p==q; else 321 if r==s; else 999 if not) :-) -- g
Gareth McCaughan
The reason I like "a if b else c" is because it has the most natural word order. In English, My dog is happy if he has a bone, else sad. sounds much more natural than My dog is, if he has a bone, happy, else sad.
Neither sounds very natural to me; conditional expressions don't occur much in English. It's much more common to hear something like
My dog is happy if he has a bone; otherwise he's sad.
Natural english wise, this also sounds natural: If my dog has a bone he's happy, otherwise he's sad. But yeah, I'll use them regardless of the syntax, even if I have preferences. - Josiah
I think I'd prefer (if <expr> then <expr> else <expre>) i.e. no colons.
My problem with this syntax is that it can be hard to read:
return if self.arg is None then default else self.arg
looks worryingly like
return NAME NAME.NAME NAME NAME NAME NAME NAME NAME.NAME
That can already be written in Python: return self.arg or default And maybe the syntax of the future conditional operator could be extended so that: return self.arg else default Would be equivalent to the previous line. For stuff were a conditional expression really is needed, like in: return if self.arg then "yes" else "no" One would hope that whoever writes the conditional expression doesn't make the expressions so long and complicated that it looks like NAME NAME.NAME NAME... It doesn't matter which syntax proposal that wins, it will still be very tempting to write unreadable code with it (think nested/chained conditional expressions). That (and the fact that I've never felt a real need for a conditional expression thanks to the "or" operator) is my very humble argument against it. -- mvh Björn
BJörn Lindqvist
My problem with this syntax is that it can be hard to read:
return if self.arg is None then default else self.arg
looks worryingly like
return NAME NAME.NAME NAME NAME NAME NAME NAME NAME.NAME
That can already be written in Python:
No it can't! Would you believe I had this exact conversation two and a half years ago? :)
return self.arg or default
Consider what happens if self.arg is 0, here. Cheers, mwh -- If I had wanted your website to make noise I would have licked my finger and rubbed it across the monitor. -- signature of "istartedi" on slashdot.org
My problem with this syntax is that it can be hard to read:
return if self.arg is None then default else self.arg
looks worryingly like
return NAME NAME.NAME NAME NAME NAME NAME NAME NAME.NAME
to me.
Interesting. What about return if self.arg is None: default else: self.arg ?
"Andrew Koenig"
My problem with this syntax is that it can be hard to read:
return if self.arg is None then default else self.arg
looks worryingly like
return NAME NAME.NAME NAME NAME NAME NAME NAME NAME.NAME
to me.
Interesting. What about
return if self.arg is None: default else: self.arg
That's awful. It would confuse everyone as to why LCs and GEs don't have punctuation while these do. In that sense, I am not convinced that it should have keywords AND punctuation, one or the other. - Josiah
[Guido van Rossum]
In fact, I think Raymond's example is more properly considered an argument for adding a conditional expression than for removing the current behavior of the and/or shortcut operators; had we had a conditional expression, he wouldn't have tried to use the "x and y or z" syntax that bit him.
[Terry Reedy]
I agree.
Me too.
Given the later addition of generator expressions with mandatory parentheses , the mandatory-parentheses version of a conditional expression looks less strange to me than it did then ;-).
Same here. Raymond
Terry Reedy wrote:
"The original version of this PEP proposed the following syntax: <expression1> if <condition> else <expression2> The out-of-order arrangement was found to be too uncomfortable for many of participants in the discussion; especially when <expression1> is long, it's easy to miss the conditional while skimming."
Guido wrote that while he was in listen-to-the-masses mode. If he's switched back to follow-my-instincts mode, it may need to be re-evaluated. -- Greg Ewing, Computer Science Dept, +--------------------------------------+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | greg.ewing@canterbury.ac.nz +--------------------------------------+
Would this change break x < y < z ? Hope not.
+1 on x?y:z
-1 on && || replacing and/or
unless and/or kept with current semantics and
&& || introduced Raymond's boolean idea, but then
-1 too many unrelated but different spellings
On 9/19/05, Guido van Rossum
On 9/19/05, Raymond Hettinger
wrote: I propose that in Py3.0, the "and" and "or" operators be simplified to always return a Boolean value instead of returning the last evaluated argument.
While you're at it, maybe we should switch to && and || as well? That's another thing I always mistype when switching between languages...
Also, this proposal needs to be considered together with the addition of a proper conditional operator, like x?y:z.
-- --Guido van Rossum (home page: http://www.python.org/~guido/) _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/ldlandis%40gmail.com
-- LD Landis - N0YRQ - from the St Paul side of Minneapolis
P.S. Simplifying "and" and "or" may create a need to introduce a conditional operator but that is a discussion for another day.
While I don't disagree with some of your main points, I do think that your proposal would eliminate a natural and easy to understand use of the current behavior of "or" that I tend to use quite a bit. Your proposal would break a lot of code, and I can't think of a better "conditional operator" than the one thats already there. I often find myself using 'or' to conditionally select a meaningful value in the absence of a real value: person = Person.fetch(id=5) name = person.name or 'John Doe' birth_date = person.birth_date or '00-00-0000' ssn = person.social_security or 'not provided' logger.log_msg('%s born on %s with SSN %s' % (name, birth_date, ssn)) To me, its just as natural as: { 'key' : value }.get('not_there', 'default') but more general purpose. I like the current behavior, and I think it makes a whole lot of sense. Jonathan LaCour http://cleverdevil.org
While I don't disagree with some of your main points, I do think that your proposal would eliminate a natural and easy to understand use of the current behavior of "or" that I tend to use quite a bit. Your proposal would break a lot of code, and I can't think of a better "conditional operator" than the one thats already there.
I often find myself using 'or' to conditionally select a meaningful value in the absence of a real value:
I agree. I find I often have an object with an optional friendly name (label) and a manditory system name. So this sort of thing becomes common: '%s blah blah' % (foo.label or foo.name) The if-else-expression alternative works, but isn't quite as readable: '%s blah blah' % (foo.label ? foo.label : foo.name) -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/
On 9/19/05, Andrew McNamara
I agree. I find I often have an object with an optional friendly name (label) and a manditory system name. So this sort of thing becomes common:
'%s blah blah' % (foo.label or foo.name)
The if-else-expression alternative works, but isn't quite as readable:
'%s blah blah' % (foo.label ? foo.label : foo.name)
Where does this work?
On Mon, Sep 19, 2005, Jonathan LaCour wrote:
Raymond Hettinger:
P.S. Simplifying "and" and "or" may create a need to introduce a conditional operator but that is a discussion for another day.
While I don't disagree with some of your main points, I do think that your proposal would eliminate a natural and easy to understand use of the current behavior of "or" that I tend to use quite a bit. Your proposal would break a lot of code, and I can't think of a better "conditional operator" than the one thats already there.
I often find myself using 'or' to conditionally select a meaningful value in the absence of a real value:
person = Person.fetch(id=5) name = person.name or 'John Doe' birth_date = person.birth_date or '00-00-0000' ssn = person.social_security or 'not provided'
While I'm in philosophical agreement with Raymond, it's also true that my current company's code is littered with constructs like yours. So I have to say that it would break too much code. -- Aahz (aahz@pythoncraft.com) <*> http://www.pythoncraft.com/ The way to build large Python applications is to componentize and loosely-couple the hell out of everything.
[Raymond Hettinger]
I propose that in Py3.0, the "and" and "or" operators be simplified to always return a Boolean value instead of returning the last evaluated argument.
1) The construct can be error-prone. When an error occurs it can be invisible to the person who wrote it. I got bitten in published code that had survived testing and code review:
def real(self): 'Return a vector with the real part of each input element' # do not convert integer inputs to floats return self.map(lambda z: type(z)==types.ComplexType and z.real or z)
The real problem, above, is the starve for using `lambda'. The abuse of `and' and `or' is a mere consequence of this. Remove `lambda' from Python, and most reasonable people would spontaneously write more legible code instead. I do not perceive Python as designed to prevent unreasonable people from "outclevering" themselves.
2) When going back and forth between languages, it is easy to forget that only Python returns something other than a boolean.
C, C++, Lisp, and shells do the same as Python. Or maybe more correctly, Python borrowed short-circuiting booleans from other languages.
3) Even when it isn't being used, the possibility of non-boolean return value complicates the bytecode and parser. [...] P.S. Simplifying "and" and "or" may create a need to introduce a conditional operator but that is a discussion for another day.
If removed, to be re-introduced differently, the bytecode and parser would not have gained simplicity overall.
Executive summary. Returning only Booleans reduces errors, makes the code easier to review, follows other language norms, and simplifies/speeds-up the generated code.
The summary reduces to: "Returning only Booleans would speed-up the generated code, once in a while." Now, could we evaluate that speed up on the average code, like on the Python library say? It might not be worth the change... -- François Pinard http://pinard.progiciels-bpi.ca
Raymond Hettinger wrote:
I propose that in Py3.0, the "and" and "or" operators be simplified to always return a Boolean value instead of returning the last evaluated argument.
1) The construct can be error-prone. When an error occurs it can be invisible to the person who wrote it. I got bitten in published code that had survived testing and code review:
Yes, I wondered about that possibility myself. +1
P.S. Simplifying "and" and "or" may create a need to introduce a conditional operator but that is a discussion for another day.
You would still be able to use multiply to covert a comparison to a value. Cheers, Ron
Raymond Hettinger wrote:
I propose that in Py3.0, the "and" and "or" operators be simplified to always return a Boolean value instead of returning the last evaluated argument.
But then I would no longer be able to write foo = something or default_value which is one of my favourite Pythonisms!
3) Even when it isn't being used, the possibility of non-boolean return value complicates the bytecode and parser. To allow for "and/or", the conditional opcodes leave the tested value on the stack. In most cases both branches go directly to a POP_TOP instruction. Since the POP_TOP shouldn't be executed twice, the body of the positive branch has to close with a jump over the other branch even when it is empty.
The solution to that is for the normal conditional opcodes to pop the stack, and to introduce separate bytecodes for implementing 'and' and 'or'. No need to change the language because of this. -- Greg Ewing, Computer Science Dept, +--------------------------------------+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | greg.ewing@canterbury.ac.nz +--------------------------------------+
3) Even when it isn't being used, the possibility of non-boolean return value complicates the bytecode and parser. To allow for "and/or", the conditional opcodes leave the tested value on the stack. In most cases both branches go directly to a POP_TOP instruction. Since the POP_TOP shouldn't be executed twice, the body of the positive branch has to close with a jump over the other branch even when it is empty.
The solution to that is for the normal conditional opcodes to pop the stack, and to introduce separate bytecodes for implementing 'and' and 'or'.
You're right. The bytecode code be fixed-up right now with no change to the language :-) That leaves error reduction and clarity as the main motivations for changing 'and' and 'or' to act like '&&' and '||' and for introducing a conditional operator to handle everyone's favorite use cases. Raymond
That leaves error reduction and clarity as the main motivations for changing 'and' and 'or' to act like '&&' and '||' and for introducing a conditional operator to handle everyone's favorite use cases.
I predict that people who use "and" and "or" correctly today will start confusing "&&" with "&" and "||" with "|", which in many instances will pass silently. In fact, I'll wager that lots of people who are familiar with boolean and/or will have never used bitwise and/or. Skip
Greg Ewing
Raymond Hettinger wrote:
I propose that in Py3.0, the "and" and "or" operators be simplified to always return a Boolean value instead of returning the last evaluated argument.
But then I would no longer be able to write
foo = something or default_value
which is one of my favourite Pythonisms!
Same here. I use this frequently. In fact, I sometimes use it in preference to a default param in {}.get(): foo = somedict.get("blarg") or expensive_default() That way the expensive default isn't calculated unless you need it. (Of course, the dict has to only store values that evaluate to non-False, which might not be possible in all situations.) Skip
On 9/19/05, Raymond Hettinger
I propose that in Py3.0, the "and" and "or" operators be simplified to always return a Boolean value instead of returning the last evaluated argument.
1) The construct can be error-prone. When an error occurs it can be invisible to the person who wrote it. I got bitten in published code that had survived testing and code review:
def real(self): 'Return a vector with the real part of each input element' # do not convert integer inputs to floats return self.map(lambda z: type(z)==types.ComplexType and z.real or z)
The code fails silently when z is (0+4i). It took a good while to trace down a user reported error (when Matlab results disagreed with my matrix module results) and determine that the real() method contained an error. Even when traced down, I found it hard to see the error in the code. Now that I know what to look for, it has not happened again, but I do always have to stare hard at any "and/or" group to mentally verify each case.
I agree. While I have used the short-circuiting and the return value myself, it has often been for just fun one-liners or when it is extemely simple and I was just too lazy to write out an 'if' statement. A conditional operator is much more proper for this (and, as Guido has said in another email, should be considered as well).
2) When going back and forth between languages, it is easy to forget that only Python returns something other than a boolean.
3) Even when it isn't being used, the possibility of non-boolean return value complicates the bytecode and parser. To allow for "and/or", the conditional opcodes leave the tested value on the stack. In most cases both branches go directly to a POP_TOP instruction. Since the POP_TOP shouldn't be executed twice, the body of the positive branch has to close with a jump over the other branch even when it is empty. For instance, the simplest case:
if a: b
compiles to:
1 0 LOAD_NAME 0 (a) 3 JUMP_IF_FALSE 8 (to 14) 6 POP_TOP
2 7 LOAD_NAME 1 (b) 10 POP_TOP 11 JUMP_FORWARD 1 (to 15) >> 14 POP_TOP >> 15 LOAD_CONST 0 (None) 18 RETURN_VALUE
this could be simpler and faster:
1 0 LOAD_NAME 0 (a) 3 JUMP_IF_FALSE 8 (to 10) 2 6 LOAD_NAME 1 (b) 9 POP_TOP >> 10 LOAD_CONST 0 (None) 13 RETURN_VALUE
Executive summary. Returning only Booleans reduces errors, makes the code easier to review, follows other language norms, and simplifies/speeds-up the generated code.
Glad the simplification of the bytecode is not the only part of your proposal. =) -Brett
Raymond Hettinger wrote:
I propose that in Py3.0, the "and" and "or" operators be simplified to always return a Boolean value instead of returning the last evaluated argument.
Please no. I find things like: def __cmp__(self, other): return (cmp(self.a, other.a) or cmp(self.b, other.b) or cmp(self.c, other.c)) somehow elegant... But I don't know how this can be useful for "and" however.
1) The construct can be error-prone. When an error occurs it can be invisible to the person who wrote it. I got bitten in published code that had survived testing and code review:
def real(self): 'Return a vector with the real part of each input element' # do not convert integer inputs to floats return self.map(lambda z: type(z)==types.ComplexType and z.real or z)
As others pointed, if lambda is to be possibly removed in py3.0, it would be better to have an example not using it. FWIW, I've never had a problem with that, but however I use the feature... Quite the opposite actually, I even though about overriding and and or to build event-driving expression, which I can't... well, forget about that;)
2) When going back and forth between languages, it is easy to forget that only Python returns something other than a boolean.
Well, there's a lot of things I miss from Python when going back and forth between languages. You need a better argument to convince me to also miss that one in Python;) I think it's not reasonable to remove the feature without adding a ?: syntax. I personally like the status quo. Regards, Nicolas
"Raymond Hettinger"
2) When going back and forth between languages, it is easy to forget that only Python returns something other than a boolean.
Perl certainly works the same way and I've never heared anybody have problems with that, but that might be because Perl do have the expr?v1:v2 triary operator as well. Most Perl programs use constructs like "a = v1 or v2 or v3" (or even "a ||= v") to its advantage. Regards, Gisle
"Raymond Hettinger"
I propose that in Py3.0, the "and" and "or" operators be simplified to always return a Boolean value instead of returning the last evaluated argument.
-1
2) When going back and forth between languages, it is easy to forget that only Python returns something other than a boolean.
As others point out, this isn't true.
3) Even when it isn't being used, the possibility of non-boolean return value complicates the bytecode and parser. To allow for "and/or", the conditional opcodes leave the tested value on the stack.
Huh? I thought this was for chained expressions? Things like 1 < x < 3. I _like_ the explanation of 'and' and 'or' as they are now. They are basically control flow constructs -- and have to be to get short-circuiting to work -- and adding a coercion to bool at the end seems to add complexity, not reduce it (on some levels, anyway).
P.S. Simplifying "and" and "or" may create a need to introduce a conditional operator but that is a discussion for another day.
... which was in the past, I thought. Cheers, mwh -- The meaning of "brunch" is as yet undefined. -- Simon Booth, ucam.chat
Michael Hudson wrote:
I _like_ the explanation of 'and' and 'or' as they are now. They are basically control flow constructs -- and have to be to get short-circuiting to work -- and adding a coercion to bool at the end seems to add complexity, not reduce it (on some levels, anyway).
Agreed. However, Raymond and Brett seem to have some ideas about optimising the normal comparison bytecode without changing the semantics, which would be good.
P.S. Simplifying "and" and "or" may create a need to introduce a conditional operator but that is a discussion for another day.
... which was in the past, I thought.
C'mon, PEP 308 was fun for everybody };) The ease of writing buggy code when trying to fake a conditional operator using and/or does seem to cause the question to keep coming up despite the fate of PEP 308, though. But the only way I can ever see a conditional operator happening is if Guido simply selects which of the top 4** PEP 308 solutions he likes best and says "make it so!". Cheers, Nick. ** I say top 4, because there was daylight between the votes for the first 4 choices and all of the other PEP 308 options. And many of the pros and cons of those 4 choices are so subjective that I wouldn't expect further discussion to significantly change anyone's opinion. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia --------------------------------------------------------------- http://boredomandlaziness.blogspot.com
On Tuesday 2005-09-20 11:40, Raymond Hettinger wrote:
2) When going back and forth between languages, it is easy to forget that only Python returns something other than a boolean.
As others point out, this isn't true.
In C, C++, C#, Java, and JavaScript, what do you get when you print the result of 3 || 10?
JavaScript does the same as Python, according to section 11.11 of the EMCA standard as of December 1999, which is what I have to hand. The others you mention don't, because doing so would fit very uncomfortably with their static type systems. Those are not the only languages that exist other than Python. Perl and Ruby both have Python-like behaviour in this respect. So do all the Lisp variants I can readily check (CL, elisp, Scheme, Dylan). So does Lua. I can't, offhand, think of any dynamically typed language that doesn't behave this way. Oh, except Smalltalk, which has a radically different approach to the whole business. -- g
On 9/20/05, Michael Hudson
I _like_ the explanation of 'and' and 'or' as they are now. They are basically control flow constructs -- and have to be to get short-circuiting to work -- and adding a coercion to bool at the end seems to add complexity, not reduce it (on some levels, anyway).
If you change the definition of 'and' and 'or' to be boolean comparison operators (as Raymond is proposing) and not as control flow constructs then is it really that complicated? I think it would actually simplify things very slightly since you just say a boolean is returned instead of the last executed expression by the operator.
P.S. Simplifying "and" and "or" may create a need to introduce a conditional operator but that is a discussion for another day.
... which was in the past, I thought.
It was, but changing 'and' and 'or' does tweak the usefulness of a conditional operator. -Brett
Brett Cannon
On 9/20/05, Michael Hudson
wrote: [SNIP] I _like_ the explanation of 'and' and 'or' as they are now. They are basically control flow constructs -- and have to be to get short-circuiting to work -- and adding a coercion to bool at the end seems to add complexity, not reduce it (on some levels, anyway).
If you change the definition of 'and' and 'or' to be boolean comparison operators (as Raymond is proposing) and not as control flow constructs then is it really that complicated?
If you eliminate the short circuiting behaviour of 'or' and 'and' the mobs will be after you with torches and pitchforks (and I'll be with them).
I think it would actually simplify things very slightly since you just say a boolean is returned instead of the last executed expression by the operator.
You might as well have 'and' be a builtin, then -- or do I misread you?
P.S. Simplifying "and" and "or" may create a need to introduce a conditional operator but that is a discussion for another day.
... which was in the past, I thought.
It was, but changing 'and' and 'or' does tweak the usefulness of a conditional operator.
Another reason why it's a bad idea :) <wink> Cheers, mwh -- I've reinvented the idea of variables and types as in a programming language, something I do on every project. -- Greg Ward, September 1998
I suppose this is a dead horse now, but I will kick it one more time. Under the rubrics of "explicit is better than implicit" and "there should only be one wat to do it", I would rather see bool_val = bool(foo or bar) instead of having the "or" operator implicitly call bool() for me. There's clear value to the current semantics and it's so easy to get a boolean if you want it, I see no reason for a change. Skip
I agree with Skip. Bill
I suppose this is a dead horse now, but I will kick it one more time.
Under the rubrics of "explicit is better than implicit" and "there should only be one wat to do it", I would rather see
bool_val = bool(foo or bar)
instead of having the "or" operator implicitly call bool() for me. There's clear value to the current semantics and it's so easy to get a boolean if you want it, I see no reason for a change.
Skip
On 9/21/05, Michael Hudson
Brett Cannon
writes: On 9/20/05, Michael Hudson
wrote: [SNIP] I _like_ the explanation of 'and' and 'or' as they are now. They are basically control flow constructs -- and have to be to get short-circuiting to work -- and adding a coercion to bool at the end seems to add complexity, not reduce it (on some levels, anyway).
If you change the definition of 'and' and 'or' to be boolean comparison operators (as Raymond is proposing) and not as control flow constructs then is it really that complicated?
If you eliminate the short circuiting behaviour of 'or' and 'and' the mobs will be after you with torches and pitchforks (and I'll be with them).
I am not suggesting that at all. I would put myself on a pike first before the mob got there. =)
I think it would actually simplify things very slightly since you just say a boolean is returned instead of the last executed expression by the operator.
You might as well have 'and' be a builtin, then -- or do I misread you?
I think you might be misreading me, but since Guido seems to have made the decision that 'and' and 'or' are not changing there is no need to try to clarify.
P.S. Simplifying "and" and "or" may create a need to introduce a conditional operator but that is a discussion for another day.
... which was in the past, I thought.
It was, but changing 'and' and 'or' does tweak the usefulness of a conditional operator.
Another reason why it's a bad idea :) <wink>
=) -Brett
Raymond Hettinger wrote:
I propose that in Py3.0, the "and" and "or" operators be simplified to always return a Boolean value instead of returning the last evaluated argument.
No, please not. It's useful sometimes and doesn't hurt most times.
1) The construct can be error-prone. When an error occurs it can be invisible to the person who wrote it. I got bitten in published code that had survived testing and code review:
def real(self): 'Return a vector with the real part of each input element' # do not convert integer inputs to floats return self.map(lambda z: type(z)==types.ComplexType and z.real or z)
I'm surprised you wrote that in the first place. The "and/or conditional" is one of the few occurences where one will carefully look for false values in the "and" part.
The code fails silently when z is (0+4i). It took a good while to trace down a user reported error (when Matlab results disagreed with my matrix module results) and determine that the real() method contained an error. Even when traced down, I found it hard to see the error in the code. Now that I know what to look for, it has not happened again, but I do always have to stare hard at any "and/or" group to mentally verify each case.
[...]
P.S. Simplifying "and" and "or" may create a need to introduce a conditional operator but that is a discussion for another day.
Exactly. A conditional was turned down some time ago, for good reasons. Reinhold -- Mail address is perfectly valid!
participants (36)
-
Aahz
-
Alexander J. Kozlovsky
-
Andrew Koenig
-
Andrew McNamara
-
Antoine Pitrou
-
Barry Warsaw
-
Bill Janssen
-
BJörn Lindqvist
-
Brett Cannon
-
François Pinard
-
Fredrik Lundh
-
Gareth McCaughan
-
Gary Herron
-
Gisle Aas
-
Greg Ewing
-
Guido van Rossum
-
Jack Diederich
-
Jonathan LaCour
-
Josiah Carlson
-
LD 'Gus' Landis
-
Mark Russell
-
Martin Blais
-
Michael Hudson
-
Nick Coghlan
-
Nicolas Fleury
-
Paul Moore
-
Phillip J. Eby
-
Raymond Hettinger
-
Reinhold Birkenfeld
-
Ron Adam
-
Skip Montanaro
-
skip@pobox.com
-
Steve Holden
-
Steven Bethard
-
Terry Reedy
-
Thomas Lotze