Proposed PEP for a Conditional Expression

Michael Chermside mcherm at destiny.com
Sun Sep 9 16:42:49 CEST 2001


Included in this email is a PEP which I am putting together dealing with 
the idea of introducing a conditional expression into Python. I would 
welcome any discussion, suggestions, and/or help, sent either to this 
newsgroup under this topic, or emailed to me at <python at mcherm.com>.

For the sake of full disclosure, I'll also express my own opinion here 
(I have tried hard to keep the PEP evenhanded). With reference to the 
PEP, I find ARG_1, ARG_3, and ARG_23 unconvincing, while ARG_21, ARG_22, 
and ARG_3 all make sense to me. But for me, ARG_24 is the overwhelming 
point and convinces me that adding a conditional expression would be a 
good idea. I prefer the syntax of SPEC_2, but am certainly open to other 
ideas.

I encourage others to let me know (in a form similar to the above) what 
they find convincing or not, and please suggest new arguments that I've 
missed.

------------------- DRAFT PEP FOLLOWS ----------------------------------
PEP: NO-NUM-YET
Title: Creating a Short-Circuiting Conditional Expression
Version: $Revision: $
Last-Modified: $Date: $
Author: python at mcherm.com (Michael Chermside)
Status: Draft
Type: Standards Track
Python-Version: 2.5
Created: NOT-CREATED-YET: dd-mmm-yyyy
Post-History:


Abstract

     A Frequently Asked Question by Python newbies is "How do I do the
     equivalent of C's ?: syntax?". The answers, while fairly well
     documented, are imperfect or incomplete. Thus many have suggested
     adding some syntax to Python for this purpose. The goal of this
     PEP is to gather all of the commonly proposed options and the
     arguments both pro and con. It will thus serve as a focal point
     for discussion and perhaps even be eventually accepted or
     rejected.


Rationale

     There are quite a few arguments and rationalizations for the
     various proposals. Here we will distinguish between arguments for
     one syntactic form over another (which should appear in the
     Specification section), and arguments for or against having a
     conditional expression at all will appear here.

     XXX - After further discussion, either a community consensus will
     be reached, or the BDFL will be invited to make a pronouncement,
     at which point that conclusion will be be given here. All of the
     arguments will be retained, and comments will be added here
     saying which arguments were the most influential.


     ARG_1: Workarounds exist.
         Here are a few workarounds. See also the Python FAQ [1], and
         the cookbook [2]. First, the things that DON'T work:

         WORKAROUND_1: (this fails)
             > def cond(c, a, b):
             >     if c: return a
             >    else: return b
             > x = cond(c, a, b)
             This fails, because it does not short-circuit... the
             arguments the the function are always evaluated before
             the function is invoked. Thus, for instance, the
             following would not work properly when a == 0:
             > x = cond( a==0, DEFAULT_VAL, 100/a )

          WORKAROUND_2: (this SOMETIMES works)
             > x = c and a or b
             Because the boolean operators short circuit, this idiom
             actually works quite nicely some of the time. As long as
             you are sure that a will evaluate as true, this will do
             the trick. It's also more readable than the other working
             solutions, although it is still quite difficult to scan
             for people not familiar with the idiom. If, however, a
             evaluates as false, then this fails.

         WORKAROUND_3: (this is the most common idiom)
             > x = (c and [a] or [b])[0]
             Here we create one-element lists and index into them.
             Since [a] is definitely NOT false (it's got 1 element),
             the and-or syntax will succeed.

         WORKAROUND_4: (lambda also works)
             > x = (c and (lambda:a) or (lambda:b))()
             This is equivalent to WORKAROUND_3, but most people
             consider it to be slightly less readable, particularly
             since conditional statements are often used in lambda
             expressions, thus complicating things further.

         WORKAROUND_5: (just write it out!)
             > if c:
             >     x = a
             > else:
             >     x = b
             Of course, many people would say that just writing it out
             is probably the best solution. It can be done in 4 line,
             or in 2, like this:
             > if c: x = a
             > else: x = b
             In either case, though, this is NOT an expression, so
             using it may require creating a temporary variable and
             splitting a formula into two lines, or replacing a lambda
             expression with a named function.



     ARG_2: No need to clutter language.
         BECAUSE workarounds exist, it is really not necessary to
         clutter the language with additional ways to express the same
         thing. It is a good thing for a language to be simple, and
         Python has this, although if it keeps adding new features all
         the time, it will eventually lose it.

     ARG_3: Not a readable syntax.
         The existance of a conditional expression syntax tends to
         lead programmers astray. It encourages unreadable syntax like
         this:
             x = c1 ? c2 ? a : b : c3 ? c4 ? d : e : f
         The use of syntax like if-then-else which scans more easily
         will not help with the fundamental problem here, which is
         that structurally, conditional expressions are easily abused
         to create unreadable code. The above would be better
         expressed on multiple lines, like this:
             if c1:
                 if c2: x = a
                 else: x = b
             else:
                 if c3:
                     if c4: x = d
                     else:  x = e
                 else: x = f
         In order to encourage Python programmers to write readable
         programs, we should not allow conditional expressions.

     ARG_21: Simplifies lambda expressions.
         Lambda expressions allow one to create an annonomous function
         on the fly and, while some rail agains them, others find them
         both useful and expressive. However, they do NOT allow
         statements, only an expression. Thus, for instance, variables
         cannot be rebound in a lambda expression, since this can only
         be achieved with a statement. This is generally considered to
         be a good thing. However, since conditionals cannot (without
         this PEP) be easily utilized in an expression, they too are
         mostly unavailable in a lambda, and this restriction is one
         most lambda users would like to see lifted. Here is an
         example of the sort of code that many lambda users would like
         to be able to write:
             inverses = map( lambda x: x==0 ? "Inf" : 1.0/x, values )

     ARG_22: Makes a functional style easier.
         One nice feature of the Python language is that it allows the
         use of a number of different programming paradigms ranging
         from simple scripting to object oriented systems. One in
         particular is functional programming (or at least programming
         which uses many of the same approaches as would be used in a
         true functional language). Features like list comprehensions
         make this paradigm particularly well supported in Python.
         However, there are many places where a functional style would
         be much easier if a conditional expression were available.
         Here is a simple example:
             tags = [ s is None ? None : '<%s>' % s  for s in keys ]

     ARG_23: Lots of people ask for it.
         Lots of people ask for a conditional expression. Even if the
         other pro arguments don't convince you, what harm is there in
         settling this one? For a LONG time, we used to hear
         complaints about how Python lacked "+=", "*=" and such; now
         that it has them, the complaints have died to a trickle.
         What's wrong with just satisfying people?

      ARG_24: Clarifies intent when used for assignments.
         Compare the following bits of code:
         Sample 1:
             x = c ? a : b
         Sample 2:
             if c:
                 x = a
             else:
                 x = b
         Sample 3:
             if c:
                 x = a
             else:
                 y = b
         Notice how using the conditional expression in sample 1 meant
         that we didn't need to write "x" twice? Now, assignment
         targets are rarely complex, so we're not saving many
         keystrokes by typing "x" only once, but we ARE clarifying the
         intent. Sample 2 makes it appear as if we want to do
         DIFFERENT THINGS depending on c, when in fact, we always want
         to do the SAME thing (set x), just with different values.
         Sample 3 looks quite similar to Sample 2, but the
         programmer's intent is completely different.


Specification

     In order to try to capture the numerous suggestions that have
     been made, this section will list SEVERAL specifications, each
     with an identifying name (SPEC_x). XXX - After further
     discussion, one specification should be selected as "preferred".
     This one should be listed first, and identified in this
     paragraph.

     Arguments for or against HAVING a conditional expression are
     found in the Rationale section, the arguments here simply deal
     with different means of


     SPEC_1: Use the "C syntax".
         The following production would be added to Python syntax:
             expression:   expression ?  exprression : expression
         Since "?" is not currently used in Python, this would never
         be syntactically ambiguous. Sample: a = b ? c : d

         PRO - [familiar to programmers]
         CON - [hard to read] [not pythonic]


     SPEC_2: Use "if-then-else".
         The following production would be added to Python syntax:
             expression:  "if" expression "then" expression "else"
                          expression
         The word "then"  would become a new keyword, introduced
         gracefully through the use of a __future__ statement. I am
         currently unclear as to whether this syntax could ever be
         ambiguous.

         PRO - [readable]
         CON - [new keyword]


     SPEC_3: Use "if-then-else" without keyword.
         The same syntax would apply as in SPEC_2, except that "then"
         would not become a keyword. Instead, a special rule would
         apply (much like the "as" from import) making it a
         pseudo-keyword only after "if" and before the "then"
         pseudo-keyword or expression ":" (which would indicate that
         it was an if *statement*, not a conditional expression).

         PRO - [no new keyword]
         CON - [pseudo-keywords are confusing]


     SPEC_4: Use "if c: a else: b".
         The following production would be added to Python syntax:
             expression: "if" expression ":" expression "else" ":"
                         expression
         The famous "dangling-else" problem would NOT arise because
         the "else:" part would be mandatory.

         PRO - [might allow "if c1: a elif c2: b else: c"]
         CON - [elif thing would re-introduce dangling else problem]


     SPEC_5: Use "if(c)a:b" syntax.
         The syntax "if (condition) trueval : falseval" would be used.

         PRO -
         CON - [syntax conflict] [too many uses for () already]
               [looks like line noise]
             Current syntax allows the following:
             > b = 'val'
             > c = 1
             > if (c): b


     Precedence:
         Orthogonal to the syntax selection is the question of
         precedence. Whichever syntax is selected, this PEP proposes
         that the precedence of the conditional expression be greater
         than that of lambda, and less than that of "or" (see the
         precedence chart in the Reference Manual [2]. Thus, the
         following:
             x = a or b ? c or d : e or f
         would be parsed as
             x = (a or b) ? (c or d) : (e or f)
         rather than
             x = a or (b ? (c or d) : e) or f
         or anything else, and likewise, that:
             x = lambda: a ? b : c
         would be parsed as
             x = lambda: (a ? b : c)
         rather than
             x = (lambda: a) ? b : c

     Short Circuiting:
         Regardless of which syntax selection is made, the evaluation
         of the conditional expression will be short circuiting. That
         means that in the expression
             x = a ? b : c
         if a is true, then c will NOT be evaluated, and if a is false
         then b will NOT be evaluated. This could be defended on
         grounds that it is similar to the short circuiting booleans
         in Python, but the REAL reason is much stronger: without
         short-circuiting evaluation, most of the utility of the
         conditional expression is lost!


Reference Implementation

     No reference implementation has been completed as yet. In fact,
     no reference implementation has been begun! The implementation is
     not expected to be difficult at all, but the design decisions ARE
     hard, so there's little sense starting on an implementation until
     the PEP status is "Accepted". XXX - After the PEP is accepted (if
     it is!) please replace this paragraph with a "help wanted!" sign
     <0.1 wink>!


References

     [1] Python FAQ: Is there an equivalent of C's "?:" operator?
         http://www.python.org/doc/FAQ.html#4.16

     [2] Python Reference Manual: Precedence chart
         http://www.python.org/doc/current/ref/summary.html

     [3] Python Cookbook: "conditionals" in expressions
         http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52310


Copyright

     This document has been placed in the public domain.



Local Variables:
mode: indented-text
indent-tabs-mode: nil
End:






More information about the Python-list mailing list