conditional expressions (RE: Loop-and-a-half (Re: Curious assignment behaviour))
tim.one at home.com
Mon Oct 15 20:13:27 CEST 2001
> How did Algol 60 deal with this?
You can study it yourself if you really care:
A key difference is that Algol-60 strictly distinguished between statements
and expressions, while Python allows any expression to be used as if it were
a statement (primarily for convenience in interactive mode). So "if" at the
start of an Algol-60 statement can only mean an Algol-60 <conditional
statement> follows, never an Algol-60 <arithmetic expression>. Python can't
distinguish the expression form from the statement form until seeing "then"
> Actually, it would probably be possible to make the parens optional in
> all cases except where 'if' is the first token of the expression.
Perhaps, with enough pain. I think the parens *usually* aid readability,
though, so would be more selective about it.
> The required changes in the grammar are quite small:
> 1. Replace all rhs instances of "testlist" with "any_expression",
> *except* the first one in "expr_stmt".
> 2. Add the following production: "any_expression: testlist
> | 'if' any_expression 'then' any_expression 'else' any_expression".
Too painful: changing the production names in a dozen places has to
propagate into tools too (like parsermodule.c's verification code, and the
Lib/compiler package). Better to allow for the absence of parens in
specific contexts where they're really silly:
> (This still doesn't allow unadorned conditional expressions in
> places where "testlist" is not used, such as function arguments.)
But requiring them is silliest in
f((if 1 then 2 else 3))
[(if 1 then 2 else 3)]
etc, i.e. in the contexts that don't cater to testlists now.
> May I be the first to say - ICK!
Yes, you may.
> I have enough political problems trying to get people I know to try
> python out - adding a wart like this ( and requiring parens on this one,
> and only one expression is really a wart!) and trying to explain it to
> newbies doesn't strike me as a winner, and I've never really pined for
> this as an experienced user.
Noted. Guido thinks a conditional expression of *some* flavor is a good
idea, so you know how this ends in the end <wink>.
> Question - what happens with:
> x = (if e1 then e2 else e3,) # <--- note trailing comma
> Should be a 1 element tuple, yes?
Sorry, I don't know what you think that should do, or what "should be a 1
element tuple" means. Do you mean it should return e2 if e1 is true, and
(e3,) if e2 false? Or that it should return (e2,) if e1 is true, and (e3,)
if e2 false? If the former
x = (if e1 then e2 else (e3,))
and if the latter either
x = (if e1 then (e2,) else (e3,))
x = (if e1 then e2 else e3),
would do it.
> What happens?
SyntaxError. e1 and e2 and e3 are instances of 'test', not of 'testlist'.
> Or would you have to write:
> x = ((if e1 then e2 else e3),)
That would also work, although the outermost parens aren't necessary there.
> That's just ugly.
Singleton-tuple notation has been "ugly" since 1991; you seem here more to
be complaining about that than about conditional expressions.
> Oh, while we're being concrete about the syntax, don't forget to allow
> elif in conditional expressions!
It wasn't forgotten, it was left out. You can spell it "else if" but are
discouraged from abuse (if you need a long chain of these, you should
probably be using a dict lookup).
> Because statements are expressions in Algo68, the 'if' clause returns a
> value, and can be used as both a statement and an expression, and either
> can be squeezed onto one line or spread across multiple lines.
The model here is Algol-60, not 68.
> However, it does suggest the question: Would this new Python
> conditional expression support:
> I *like*
> if e1:
> x = e2
> x = e3
> Makes it easy to see what goes on when e1 is true or false.
The thrust is for simple cases where that construct requires introducing a
temp name that wouldn't otherwise be needed, much as "and" and "or" are
routinely used today to avoid otherwise-pointless temps.
a[i-j+1] = (if e1 then e2 else e3)
is likely clearer than
temp = e2
temp = e3
a[i-j] = temp
a[i-j+1] = e2
a[i-j+1] = e3
> Take Uncle Tim's example code
> x = (if a+b/sqrt(3) then 3**f(5, 3)- 12 else ",".join(list) + ":\n")
In context, it was an example trying to provoke someone else into spelling
out what they meant by "generalization", by showing how stupid you *can* be
with this gimmick. I wouldn't write it that way (indeed, I wouldn't write
code like that any other way either <wink>).
> There's talk of generalization. But more likely the expansion of a
> one-liner like the above is to add more statements to a branch, as
> in something like:
> if a+b/sqrt(3):
> count = count + 1
> x = 3**f(5, 3) - 12
> spam *= count
> x = ",".join(list) + ":\n"
> With the one-liner form, translation to the normal Python if/else
> statement calls for a lot of code changes.
Use any construct when it's inapproriate and you'll pay a price. There are
appropriate uses for conditional expressions, as any C, C++, Perl, Icon,
Haskell, ML, Scheme etc programmer can testify from experience (I hesitate
to say Algol-60 programmer, because I'm not sure there are any anymore! but
that's where Guido remembers it from).
> I tried looking through the thread in its various subject names.
> I couldn't figure out what was the driving reason for this idea.
> (Other than as a replacement for C's ?: ternary operator.)
> Enlightment, anyone?
It's a conditional expresssion -- that's all. It's been debated for years,
on Python-Dev most persistenly by Eric Raymond. It came up in internal
PythonLabs discussions late last week, as an offshoot of a "should we try to
reserve any other keywords for 2.2?" discussion. Guido figured it was time
to at least try it, fiddled the grammar for if/then/else, and I implemented
it over the weekend. It has not been checked in yet. If it turns into a
time sink (which it is on the edge of becoming), it will go away (if it's
not in 2.2b1 later this week, it won't go in at all).
More information about the Python-list