diff --git a/pep-0308.txt b/pep-0308.txt index 066f4a3b1..fb4b317a5 100644 --- a/pep-0308.txt +++ b/pep-0308.txt @@ -5,318 +5,332 @@ Last-Modified: $Date$ Author: Guido van Rossum, Raymond Hettinger Status: Final Type: Standards Track -Content-Type: text/plain +Content-Type: text/x-rst Created: 7-Feb-2003 Post-History: 7-Feb-2003, 11-Feb-2003 Adding a conditional expression +=============================== - On 9/29/2005, Guido decided to add conditional expressions in the - form of "X if C else Y". [1] +On 9/29/2005, Guido decided to add conditional expressions in the +form of "X if C else Y". [1]_ - The motivating use case was the prevalence of error-prone attempts - to achieve the same effect using "and" and "or". [2] +The motivating use case was the prevalence of error-prone attempts +to achieve the same effect using "and" and "or". [2]_ - Previous community efforts to add a conditional expression were - stymied by a lack of consensus on the best syntax. That issue was - resolved by simply deferring to a BDFL best judgment call. +Previous community efforts to add a conditional expression were +stymied by a lack of consensus on the best syntax. That issue was +resolved by simply deferring to a BDFL best judgment call. - The decision was validated by reviewing how the syntax fared when - applied throughout the standard library (this review approximates a - sampling of real-world use cases, across a variety of applications, - written by a number of programmers with diverse backgrounds). [3] +The decision was validated by reviewing how the syntax fared when +applied throughout the standard library (this review approximates a +sampling of real-world use cases, across a variety of applications, +written by a number of programmers with diverse backgrounds). [3]_ - The following change will be made to the grammar. (The or_test - symbols is new, the others are modified.) +The following change will be made to the grammar. (The or_test +symbols is new, the others are modified.) - test: or_test ['if' or_test 'else' test] | lambdef - or_test: and_test ('or' and_test)* - ... - testlist_safe: or_test [(',' or_test)+ [',']] - ... - gen_for: 'for' exprlist 'in' or_test [gen_iter] +:: - The new syntax nearly introduced a minor syntactical backwards - incompatibility. In previous Python versions, the following is - legal: + test: or_test ['if' or_test 'else' test] | lambdef + or_test: and_test ('or' and_test)* + ... + testlist_safe: or_test [(',' or_test)+ [',']] + ... + gen_for: 'for' exprlist 'in' or_test [gen_iter] - [f for f in lambda x: x, lambda x: x**2 if f(1) == 1] +The new syntax nearly introduced a minor syntactical backwards +incompatibility. In previous Python versions, the following is +legal:: - (I.e. a list comprehension where the sequence following 'in' is an - unparenthesized series of lambdas -- or just one lambda, even.) + [f for f in lambda x: x, lambda x: x**2 if f(1) == 1] - In Python 3.0, the series of lambdas will have to be - parenthesized, e.g.: +(I.e. a list comprehension where the sequence following 'in' is an +unparenthesized series of lambdas -- or just one lambda, even.) - [f for f in (lambda x: x, lambda x: x**2) if f(1) == 1] +In Python 3.0, the series of lambdas will have to be +parenthesized, e.g.:: - This is because lambda binds less tight than the if-else - expression, but in this context, the lambda could already be - followed by an 'if' keyword that binds less tightly still (for - details, consider the grammar changes shown above). + [f for f in (lambda x: x, lambda x: x**2) if f(1) == 1] - However, in Python 2.5, a slightly different grammar is used that - is more backwards compatible, but constrains the grammar of a - lambda used in this position by forbidding the lambda's body to - contain an unparenthesized condition expression. Examples: +This is because lambda binds less tight than the if-else +expression, but in this context, the lambda could already be +followed by an 'if' keyword that binds less tightly still (for +details, consider the grammar changes shown above). - [f for f in (1, lambda x: x if x >= 0 else -1)] # OK - [f for f in 1, (lambda x: x if x >= 0 else -1)] # OK - [f for f in 1, lambda x: (x if x >= 0 else -1)] # OK - [f for f in 1, lambda x: x if x >= 0 else -1] # INVALID +However, in Python 2.5, a slightly different grammar is used that +is more backwards compatible, but constrains the grammar of a +lambda used in this position by forbidding the lambda's body to +contain an unparenthesized condition expression. Examples:: + + [f for f in (1, lambda x: x if x >= 0 else -1)] # OK + [f for f in 1, (lambda x: x if x >= 0 else -1)] # OK + [f for f in 1, lambda x: (x if x >= 0 else -1)] # OK + [f for f in 1, lambda x: x if x >= 0 else -1] # INVALID References +========== - [1] Pronouncement - https://mail.python.org/pipermail/python-dev/2005-September/056846.html +.. [1] Pronouncement + https://mail.python.org/pipermail/python-dev/2005-September/056846.html - [2] Motivating use case: - https://mail.python.org/pipermail/python-dev/2005-September/056546.html - https://mail.python.org/pipermail/python-dev/2005-September/056510.html +.. [2] Motivating use case: + https://mail.python.org/pipermail/python-dev/2005-September/056546.html + https://mail.python.org/pipermail/python-dev/2005-September/056510.html - [3] Review in the context of real-world code fragments: - https://mail.python.org/pipermail/python-dev/2005-September/056803.html +.. [3] Review in the context of real-world code fragments: + https://mail.python.org/pipermail/python-dev/2005-September/056803.html Introduction to earlier draft of the PEP (kept for historical purposes) +======================================================================= - Requests for an if-then-else ("ternary") expression keep coming up - on comp.lang.python. This PEP contains a concrete proposal of a - fairly Pythonic syntax. This is the community's one chance: if - this PEP is approved with a clear majority, it will be implemented - in Python 2.4. If not, the PEP will be augmented with a summary - of the reasons for rejection and the subject better not come up - again. While the BDFL is co-author of this PEP, he is neither in - favor nor against this proposal; it is up to the community to - decide. If the community can't decide, the BDFL will reject the - PEP. +Requests for an if-then-else ("ternary") expression keep coming up +on comp.lang.python. This PEP contains a concrete proposal of a +fairly Pythonic syntax. This is the community's one chance: if +this PEP is approved with a clear majority, it will be implemented +in Python 2.4. If not, the PEP will be augmented with a summary +of the reasons for rejection and the subject better not come up +again. While the BDFL is co-author of this PEP, he is neither in +favor nor against this proposal; it is up to the community to +decide. If the community can't decide, the BDFL will reject the +PEP. - After unprecedented community response (very good arguments were - made both pro and con) this PEP has been revised with the help of - Raymond Hettinger. Without going through a complete revision - history, the main changes are a different proposed syntax, an - overview of proposed alternatives, the state of the curent - discussion, and a discussion of short-circuit behavior. +After unprecedented community response (very good arguments were +made both pro and con) this PEP has been revised with the help of +Raymond Hettinger. Without going through a complete revision +history, the main changes are a different proposed syntax, an +overview of proposed alternatives, the state of the curent +discussion, and a discussion of short-circuit behavior. - Following the discussion, a vote was held. While there was an overall - interest in having some form of if-then-else expressions, no one - format was able to draw majority support. Accordingly, the PEP was - rejected due to the lack of an overwhelming majority for change. - Also, a Python design principle has been to prefer the status quo - whenever there are doubts about which path to take. +Following the discussion, a vote was held. While there was an overall +interest in having some form of if-then-else expressions, no one +format was able to draw majority support. Accordingly, the PEP was +rejected due to the lack of an overwhelming majority for change. +Also, a Python design principle has been to prefer the status quo +whenever there are doubts about which path to take. Proposal +======== - The proposed syntax is as follows: +The proposed syntax is as follows:: - (if : else: ) + (if : else: ) - Note that the enclosing parentheses are not optional. +Note that the enclosing parentheses are not optional. - The resulting expression is evaluated like this: +The resulting expression is evaluated like this: - - First, is evaluated. +- First, is evaluated. - - If is true, is evaluated and is the - result of the whole thing. +- If is true, is evaluated and is the + result of the whole thing. - - If is false, is evaluated and is the - result of the whole thing. +- If is false, is evaluated and is the + result of the whole thing. - A natural extension of this syntax is to allow one or more 'elif' - parts: +A natural extension of this syntax is to allow one or more 'elif' +parts:: - (if : elif : ... else: ) + (if : elif : ... else: ) - This will be implemented if the proposal is accepted. +This will be implemented if the proposal is accepted. - The downsides to the proposal are: +The downsides to the proposal are: - * the required parentheses - * confusability with statement syntax - * additional semantic loading of colons +* the required parentheses +* confusability with statement syntax +* additional semantic loading of colons - Note that at most one of and is - evaluated. This is called a "short-circuit expression"; it is - similar to the way the second operand of 'and' / 'or' is only - evaluated if the first operand is true / false. +Note that at most one of and is +evaluated. This is called a "short-circuit expression"; it is +similar to the way the second operand of 'and' / 'or' is only +evaluated if the first operand is true / false. - A common way to emulate an if-then-else expression is: +A common way to emulate an if-then-else expression is:: - and or + and or - However, this doesn't work the same way: it returns - when is false! See FAQ 4.16 for alternatives that - work -- however, they are pretty ugly and require much more effort - to understand. +However, this doesn't work the same way: it returns +when is false! See FAQ 4.16 for alternatives that +work -- however, they are pretty ugly and require much more effort +to understand. Alternatives +============ - Holger Krekel proposed a new, minimally invasive variant: +Holger Krekel proposed a new, minimally invasive variant:: - and else + and else - The concept behind it is that a nearly complete ternary operator - already exists with and/or and this proposal is the least invasive - change that makes it complete. Many respondants on the - newsgroup found this to be the most pleasing alternative. - However, a couple of respondants were able to post examples - that were mentally difficult to parse. Later it was pointed - out that this construct works by having the "else" change the - existing meaning of "and". +The concept behind it is that a nearly complete ternary operator +already exists with and/or and this proposal is the least invasive +change that makes it complete. Many respondants on the +newsgroup found this to be the most pleasing alternative. +However, a couple of respondants were able to post examples +that were mentally difficult to parse. Later it was pointed +out that this construct works by having the "else" change the +existing meaning of "and". - As a result, there is increasing support for Christian Tismer's - proposed variant of the same idea: +As a result, there is increasing support for Christian Tismer's +proposed variant of the same idea:: - then else + then else - The advantages are simple visual parsing, no required parentheses, - no change in the semantics of existing keywords, not as likely - as the proposal to be confused with statement syntax, and does - not further overload the colon. The disadvantage is the - implementation costs of introducing a new keyword. However, - unlike other new keywords, the word "then" seems unlikely to - have been used as a name in existing programs. +The advantages are simple visual parsing, no required parentheses, +no change in the semantics of existing keywords, not as likely +as the proposal to be confused with statement syntax, and does +not further overload the colon. The disadvantage is the +implementation costs of introducing a new keyword. However, +unlike other new keywords, the word "then" seems unlikely to +have been used as a name in existing programs. - --- +--- - Many C-derived languages use this syntax: +Many C-derived languages use this syntax:: - ? : + ? : - Eric Raymond even implemented this. The BDFL rejected this for - several reasons: the colon already has many uses in Python (even - though it would actually not be ambiguous, because the question - mark requires a matching colon); for people not used to C-derived - language, it is hard to understand. +Eric Raymond even implemented this. The BDFL rejected this for +several reasons: the colon already has many uses in Python (even +though it would actually not be ambiguous, because the question +mark requires a matching colon); for people not used to C-derived +language, it is hard to understand. - --- +--- - The original version of this PEP proposed the following syntax: +The original version of this PEP proposed the following syntax:: - if else + if else - The out-of-order arrangement was found to be too uncomfortable - for many of participants in the discussion; especially when - is long, it's easy to miss the conditional while - skimming. +The out-of-order arrangement was found to be too uncomfortable +for many of participants in the discussion; especially when + is long, it's easy to miss the conditional while +skimming. - --- +--- - Some have suggested adding a new builtin instead of extending the - syntax of the language. For example: +Some have suggested adding a new builtin instead of extending the +syntax of the language. For example:: - cond(, , ) + cond(, , ) - This won't work the way a syntax extension will because both - expression1 and expression2 must be evaluated before the function - is called. There's no way to short-circuit the expression - evaluation. It could work if 'cond' (or some other name) were - made a keyword, but that has all the disadvantages of adding a new - keyword, plus confusing syntax: it *looks* like a function call so - a casual reader might expect both and - to be evaluated. +This won't work the way a syntax extension will because both +expression1 and expression2 must be evaluated before the function +is called. There's no way to short-circuit the expression +evaluation. It could work if 'cond' (or some other name) were +made a keyword, but that has all the disadvantages of adding a new +keyword, plus confusing syntax: it **looks** like a function call so +a casual reader might expect both and +to be evaluated. Summary of the Current State of the Discussion +============================================== - Groups are falling into one of three camps: +Groups are falling into one of three camps: - 1. Adopt a ternary operator built using punctuation characters: +1. Adopt a ternary operator built using punctuation characters:: - ? : + ? : - 2. Adopt a ternary operator built using new or existing keywords. - The leading examples are: +2. Adopt a ternary operator built using new or existing keywords. + The leading examples are:: - then else - (if : else: ) + then else + (if : else: ) - 3. Do nothing. +3. Do nothing. - The first two positions are relatively similar. +The first two positions are relatively similar. - Some find that any form of punctuation makes the language more - cryptic. Others find that punctuation style is appropriate for - expressions rather than statements and helps avoid a COBOL style: - 3 plus 4 times 5. +Some find that any form of punctuation makes the language more +cryptic. Others find that punctuation style is appropriate for +expressions rather than statements and helps avoid a COBOL style: +3 plus 4 times 5. - Adapting existing keywords attempts to improve on punctuation - through explicit meaning and a more tidy appearance. The downside - is some loss of the economy-of-expression provided by punctuation - operators. The other downside is that it creates some degree of - confusion between the two meanings and two usages of the keywords. +Adapting existing keywords attempts to improve on punctuation +through explicit meaning and a more tidy appearance. The downside +is some loss of the economy-of-expression provided by punctuation +operators. The other downside is that it creates some degree of +confusion between the two meanings and two usages of the keywords. - Those difficulties are overcome by options which introduce new - keywords which take more effort to implement. +Those difficulties are overcome by options which introduce new +keywords which take more effort to implement. - The last position is doing nothing. Arguments in favor include - keeping the language simple and concise; maintaining backwards - compatibility; and that any every use case can already be already - expressed in terms of "if" and "else". Lambda expressions are an - exception as they require the conditional to be factored out into - a separate function definition. +The last position is doing nothing. Arguments in favor include +keeping the language simple and concise; maintaining backwards +compatibility; and that any every use case can already be already +expressed in terms of "if" and "else". Lambda expressions are an +exception as they require the conditional to be factored out into +a separate function definition. - The arguments against doing nothing are that the other choices - allow greater economy of expression and that current practices - show a propensity for erroneous uses of "and", "or", or one their - more complex, less visually unappealing workarounds. +The arguments against doing nothing are that the other choices +allow greater economy of expression and that current practices +show a propensity for erroneous uses of "and", "or", or one their +more complex, less visually unappealing workarounds. Short-Circuit Behavior +====================== - The principal difference between the ternary operator and the - cond() function is that the latter provides an expression form but - does not provide short-circuit evaluation. +The principal difference between the ternary operator and the +``cond()`` function is that the latter provides an expression form but +does not provide short-circuit evaluation. - Short-circuit evaluation is desirable on three occasions: +Short-circuit evaluation is desirable on three occasions: - 1. When an expression has side-effects - 2. When one or both of the expressions are resource intensive - 3. When the condition serves as a guard for the validity of the - expression. +1. When an expression has side-effects +2. When one or both of the expressions are resource intensive +3. When the condition serves as a guard for the validity of the + expression. + +:: # Example where all three reasons apply data = isinstance(source, file) ? source.readlines() : source.split() - 1. readlines() moves the file pointer - 2. for long sources, both alternatives take time - 3. split() is only valid for strings and readlines() is only - valid for file objects. +1. ``readlines()`` moves the file pointer +2. for long sources, both alternatives take time +3. ``split()`` is only valid for strings and ``readlines()`` is only + valid for file objects. - Supporters of a cond() function point out that the need for - short-circuit evaluation is rare. Scanning through existing code - directories, they found that if/else did not occur often; and of - those only a few contained expressions that could be helped by - cond() or a ternary operator; and that most of those had no need - for short-circuit evaluation. Hence, cond() would suffice for - most needs and would spare efforts to alter the syntax of the - language. +Supporters of a ``cond()`` function point out that the need for +short-circuit evaluation is rare. Scanning through existing code +directories, they found that if/else did not occur often; and of +those only a few contained expressions that could be helped by +``cond()`` or a ternary operator; and that most of those had no need +for short-circuit evaluation. Hence, ``cond()`` would suffice for +most needs and would spare efforts to alter the syntax of the +language. - More supporting evidence comes from scans of C code bases which - show that its ternary operator used very rarely (as a percentage - of lines of code). +More supporting evidence comes from scans of C code bases which +show that its ternary operator used very rarely (as a percentage +of lines of code). - A counterpoint to that analysis is that the availability of a - ternary operator helped the programmer in every case because it - spared the need to search for side-effects. Further, it would - preclude errors arising from distant modifications which introduce - side-effects. The latter case has become more of a reality with - the advent of properties where even attribute access can be given - side-effects. +A counterpoint to that analysis is that the availability of a +ternary operator helped the programmer in every case because it +spared the need to search for side-effects. Further, it would +preclude errors arising from distant modifications which introduce +side-effects. The latter case has become more of a reality with +the advent of properties where even attribute access can be given +side-effects. - The BDFL's position is that short-circuit behavior is essential - for an if-then-else construct to be added to the language. +The BDFL's position is that short-circuit behavior is essential +for an if-then-else construct to be added to the language. Detailed Results of Voting +========================== +:: + Votes rejecting all options: 82 Votes with rank ordering: 436 --- @@ -352,8 +366,11 @@ Detailed Results of Voting Total 363 286 202 155 231 312 1549 - CHOICE KEY - ---------- +CHOICE KEY +---------- + +:: + A. x if C else y B. if C then x else y C. (if C: x else: y) @@ -373,8 +390,11 @@ Detailed Results of Voting Q. any write-in vote - Detail for write-in votes and their ranking: - -------------------------------------------- +Detail for write-in votes and their ranking +-------------------------------------------- + +:: + 3: Q reject y x C elsethenif 2: Q accept (C ? x ! y) 3: Q reject ... @@ -440,14 +460,15 @@ Detailed Results of Voting Copyright +========= - This document has been placed in the public domain. +This document has been placed in the public domain. - -Local Variables: -mode: indented-text -indent-tabs-mode: nil -sentence-end-double-space: t -fill-column: 70 -End: +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + End: