PEP: 308 Title: If-then-else expression Version: $Revision$ Last-Modified: $Date$ Author: Guido van Rossum, Raymond D. Hettinger Status: Draft Type: Standards Track Content-Type: text/plain Created: 7-Feb-2003 Post-History: 7-Feb-2003, 11-Feb-2003 Introduction 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. Proposal The proposed syntax is as follows: (if : else: ) Note that the enclosing parentheses are not optional. The resulting expression is evaluated like this: - First, is evaluated. - 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. A natural extension of this syntax is to allow one or more 'elif' parts: (if : elif : ... else: ) This will be implemented if the proposal is accepted. The downsides to the proposal are: * 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. A common way to emulate an if-then-else expression is: 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. Alternatives Holger Krekel proposed a new, minimally invasive variant: 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". As a result, there is increasing support for Christian Tismer's proposed variant of the same idea: then else The advantages are simple visual parsing, no required parenthesis, 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: ? : 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: 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. --- Some have suggested adding a new builtin instead of extending the syntax of the language. For example: 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. 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: ? : 2. Adopt a ternary operator built using new or existing keywords. The leading examples are: then else (if : else: ) 3. Do nothing. 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. 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. 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. 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. 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. # 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. 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). A counter point 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. Copyright 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: