Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

PEP 308: some candidate uses cases from live code

0 views
Skip to first unread message

Martin Maney

unread,
Feb 9, 2003, 3:10:17 AM2/9/03
to
Okay, a bleary-eyed survey of about 4000 lines of code from a project
I've been working on in odd bits of time. Best Available Data, sir,
but mine own. <wink>

These are the uses of a simple if/else that seemed to me to be at least
vaguely suitable for the proposed ternary operator; most of the if/else
occurences rejected were over four lines or had very little in common
between the if and the else code. I don't believe I omitted any that
weren't less good candidates than the ones below.

If you think my commentary reveals an imperfectly consistent view of
the proper use and value of 308's ternary, you may be right. I worked
on this intermittently over the last few hours, and I haven't gone back
and "corrected" anything [though I may add a note like this before I
send this off] just because I was learning how I liked this as I went
along.


Candidate 1 - this is from a simple "one line == one record" CSV parser

else:
start = i
j = s.find(',', i)
if j >= 0:
i = j
else:
i = n
field = s[start:i]

About all that could be changed here is collapsing the if/else, as i is
live past the end of the code shown:

else:
start = i
j = s.find(',', i)
i = j if j >= 0 else n
field = s[start:i]

I don't find this very convincing, but it has its points. I wrote it so
as to keep the condition the same, and it's just coincidence that that
made it come out with the pleasing "j if j >= 0 ..." form. At least I
find it pleasing. Is that line harder to understand than any one of the
original lines? Of course. Is it harder to understand than the total
effect of the four lines it replaces?


Candidate 2 - generating bounding dates for a month

first = '%04d-%02d-01' % (year, month)
if (month < 12):
last = '%04d-%02d-01' % (year, month + 1)
else:
last = '%04d-01-01' % (year + 1)

Not really a very promising candidate: there's too much that's different
between the two values for this to appeal to me. This was the second
plausible candidate I found after sifting through a lot of Python with
no simple if/else constructs. Of course a lot of the code I've been
looking at was written knowing that ternary wasn't a viable option (I
have used one or another of the kulges a few times, but generally find
them uglier than four not-quite-emtpy lines of code.)


Candidate 3 - calculate "school year" from year & month

if d0.month < 7:
sy = d0.year - 1
else:
sy = d0.year

Becomes, after a little rearrangement:

sy = d0.year - (1 if d0.month < 7 else 0)

I think this actually expresses the original logic a little more
clearly: the school year is the day's year unless the day's month is
January through June; then one must be subtracted to get the calendar
year during which the school year began.


Candidate 4 - preparing to use an optional parameter in generated HTML

if params.has_key('add2url'):
add2url = '?' + params['add2url']
else:
add2url = ''

Could be expressed as

add2url = '?' + params['add2url'] if params.has_key('add2url') else ''

This is an example where the short-circuit behavior is important, but
it's not a terribly convincing example overall since it could easily
be written as

add2url = ''
if params.has_key('add2url'):
add2url = '?' + params['add2url']

This last is almost certainly how I would write this, as there's no
concrete advantage IMO to the ternary form here. I think I was using
a common pattern for all setup items in this routine and/or module.

[later: "certainly"? well, maybe, but maybe not]


Candidate 5 - another bit from HTML generation

if len(events) > 1:
sep = ' '
else:
sep = '<br>'

Obvious:

sep = ' ' if len(events) > 1 else '<br>'

In a larger context, this would actually allow me to do away with the
'sep' temporary:

if len(events) > 1:
sep = ' '
else:
sep = '<br>'
...
if tail:
tail = sep + tail

allowing a considerable reduction:

...
if tail:
tail = (' ' if len(events) > 1 else '<br>') + tail

I'm not sure why the calculation of 'sep' was separated from its use
in the code. This is older code that's been through a couple waves of
refactorings of the system its part of; possibly 'sep' used to be used
in more than one location in an earlier version. Perhaps the inlined
version above should be compared to this rather than the original:

...
if tail:
if len(events) > 1:
tail = ' ' + tail
else:
tail = '<br>' + tail


Candidate 6 - again, HTML generation

if colors:
color = 'bgcolor=%s' % colors[gr % len(colors)]
else:
color = ''

Naturally:

color = 'bgcolor=%s' % colors[gr % len(colors)] if colors else ''

Hmmm... what precedence does ternary have, again? The previous item
just seemed to obviously need the parens; this one I'm not so sure
about.


Summary:

I didn't find nearly as many simple if/else uses as I had expected to
in this project's code. What else have I been working on recently that
might account for this persistent notion that I ought to have better
examples than most of these?

The other thing I discovered was that some of the older modules really
need a good, brisk currying - I came across a few things that made me
wince. Oh, and Aahz, I know you'll want to hear about this: a couple
modules with some map'n'filter'n'lambda uses that I'm certain will look
a lot better as list comprehensions. :-)

Amazing how dated six month old code can look...

Tim Peters

unread,
Feb 9, 2003, 3:53:41 AM2/9/03
to
[Martin Maney]
> ...

> Candidate 3 - calculate "school year" from year & month
>
> if d0.month < 7:
> sy = d0.year - 1
> else:
> sy = d0.year
>
> Becomes, after a little rearrangement:
>
> sy = d0.year - (1 if d0.month < 7 else 0)
>
> I think this actually expresses the original logic a little more
> clearly: the school year is the day's year unless the day's month is
> January through June; then one must be subtracted to get the calendar
> year during which the school year began.

Me too, but note that it could be written (even in Python 1.0):

sy = d0.year - (d0.month < 7)

That bools are confusable with 0 and 1 in Python is A Feature.

Bengt Richter

unread,
Feb 9, 2003, 7:37:48 AM2/9/03
to

field = s[start:(j<0?j,n)] # cond ? false_sel, true_sel

> i = j if j >= 0 else n
> field = s[start:i]
>
> I don't find this very convincing, but it has its points. I wrote it so
> as to keep the condition the same, and it's just coincidence that that
> made it come out with the pleasing "j if j >= 0 ..." form. At least I
> find it pleasing. Is that line harder to understand than any one of the
> original lines? Of course. Is it harder to understand than the total
> effect of the four lines it replaces?
>
>
>Candidate 2 - generating bounding dates for a month
>
> first = '%04d-%02d-01' % (year, month)

last = '%04d-%02d-01' % (month<12? (year+1, 1), (year, month+1))

> if (month < 12):
> last = '%04d-%02d-01' % (year, month + 1)
> else:
> last = '%04d-01-01' % (year + 1)
>
> Not really a very promising candidate: there's too much that's different
> between the two values for this to appeal to me. This was the second
> plausible candidate I found after sifting through a lot of Python with
> no simple if/else constructs. Of course a lot of the code I've been
> looking at was written knowing that ternary wasn't a viable option (I
> have used one or another of the kulges a few times, but generally find
> them uglier than four not-quite-emtpy lines of code.)
>
>
>Candidate 3 - calculate "school year" from year & month
>
> if d0.month < 7:
> sy = d0.year - 1
> else:
> sy = d0.year
>
> Becomes, after a little rearrangement:
>
> sy = d0.year - (1 if d0.month < 7 else 0)

sy = d0.year - (d0.month < 7) # this is already 1 or 0

sy = d0.year - (d0.month < 7 ? 0, 1) # this is already 1 or 0
sy = d0.month<7 ? d0.year, d0.year-1 # alternative form

>
> I think this actually expresses the original logic a little more
> clearly: the school year is the day's year unless the day's month is
> January through June; then one must be subtracted to get the calendar
> year during which the school year began.
>
>
>Candidate 4 - preparing to use an optional parameter in generated HTML
>
> if params.has_key('add2url'):
> add2url = '?' + params['add2url']
> else:
> add2url = ''
>
> Could be expressed as
>
> add2url = '?' + params['add2url'] if params.has_key('add2url') else ''

add2url = params.has_key('add2url') ? '', '?'+params['add2url']

>
> This is an example where the short-circuit behavior is important, but
> it's not a terribly convincing example overall since it could easily
> be written as
>
> add2url = ''
> if params.has_key('add2url'):
> add2url = '?' + params['add2url']
>
> This last is almost certainly how I would write this, as there's no
> concrete advantage IMO to the ternary form here. I think I was using
> a common pattern for all setup items in this routine and/or module.
>
> [later: "certainly"? well, maybe, but maybe not]
>
>
>Candidate 5 - another bit from HTML generation
>
> if len(events) > 1:
> sep = ' '
> else:
> sep = '<br>'
>
> Obvious:
>
> sep = ' ' if len(events) > 1 else '<br>'

sep = len(events) > 1 ? '<br>', ' '


>
> In a larger context, this would actually allow me to do away with the
> 'sep' temporary:
>
> if len(events) > 1:
> sep = ' '
> else:
> sep = '<br>'
> ...
> if tail:
> tail = sep + tail
>
> allowing a considerable reduction:
>
> ...
> if tail:
> tail = (' ' if len(events) > 1 else '<br>') + tail

tail = (len(events) > 1 ? '<br>', ' ') + tail


>
> I'm not sure why the calculation of 'sep' was separated from its use
> in the code. This is older code that's been through a couple waves of
> refactorings of the system its part of; possibly 'sep' used to be used
> in more than one location in an earlier version. Perhaps the inlined
> version above should be compared to this rather than the original:
>
> ...
> if tail:
> if len(events) > 1:
> tail = ' ' + tail
> else:
> tail = '<br>' + tail
>
>
>Candidate 6 - again, HTML generation
>
> if colors:
> color = 'bgcolor=%s' % colors[gr % len(colors)]
> else:
> color = ''
>
> Naturally:
>
> color = 'bgcolor=%s' % colors[gr % len(colors)] if colors else ''

color = colors? '', 'bgcolor=%s' % colors[gr % len(colors)]


>
> Hmmm... what precedence does ternary have, again? The previous item
> just seemed to obviously need the parens; this one I'm not so sure
> about.
>
>
>Summary:
>
> I didn't find nearly as many simple if/else uses as I had expected to
> in this project's code. What else have I been working on recently that
> might account for this persistent notion that I ought to have better
> examples than most of these?
>
> The other thing I discovered was that some of the older modules really
> need a good, brisk currying - I came across a few things that made me
> wince. Oh, and Aahz, I know you'll want to hear about this: a couple
> modules with some map'n'filter'n'lambda uses that I'm certain will look
> a lot better as list comprehensions. :-)
>
> Amazing how dated six month old code can look...
>

Regards,
Bengt Richter

Carlos Ribeiro

unread,
Feb 9, 2003, 2:09:35 PM2/9/03
to
On Sunday 09 February 2003 06:53, Tim Peters wrote:
> Me too, but note that it could be written (even in Python 1.0):
>
> sy = d0.year - (d0.month < 7)
>
> That bools are confusable with 0 and 1 in Python is A Feature.

While I know it, and I've used it... it still does not seem the best thing to
do in name of readability and maintainability. I prefer the conditional
statement, because it clearly expresses the underlying logic, to any use of a
side effect as mentioned above. But that's me, your mileage may vary.

[btw, I believe that this has something to do with the fact that my first
language was Pascal, where the true=1/false=0 identity doesn't hold by
definition. C programmers are more used to this idiom than I am]


Carlos Ribeiro
crib...@mail.inet.com.br

Martin Maney

unread,
Feb 9, 2003, 7:08:00 PM2/9/03
to
Bengt Richter <bo...@oz.net> wrote:
> On Sun, 9 Feb 2003 08:10:17 +0000 (UTC), Martin Maney <ma...@pobox.com> wrote:
>> About all that could be changed here is collapsing the if/else, as i is
>> live past the end of the code shown:
>>
>> else:
>> start = i
>> j = s.find(',', i)
> field = s[start:(j<0?j,n)] # cond ? false_sel, true_sel

Except as I said, hoping to forestall this very misunderstanding, i is
live at the end of this code, so you can't skip its assignment. So
what you meant to say would be

>> i = j if j >= 0 else n
>> field = s[start:i]

i = (j < 0 ? j, n)


field = s[start:i]

BTW, the false and true are given backwards in your proposal. <wink>
-1 on that ordering, +0 on the form with corrected ordering. The
parentheses are okay, the question mark is "obvious", but the comma is
too nearly invisble to please me.

>>Candidate 2 - generating bounding dates for a month
>>
>> first = '%04d-%02d-01' % (year, month)
> last = '%04d-%02d-01' % (month<12? (year+1, 1), (year, month+1))

Yeah, now let's try writing it with readable spaces:

last = "%04d-%02d-01' % (month < 12 ? (year + 1, 1), (year, month + 1))

I still don't care for it. It makes it much harder to see what is
actually different between the two cases. Of course that's equally
true no matter what form the ternary takes.

>> sy = d0.year - (1 if d0.month < 7 else 0)
> sy = d0.year - (d0.month < 7) # this is already 1 or 0

Bad trick. Page has been ripped out of playbook long since. :-(

> sy = d0.year - (d0.month < 7 ? 0, 1) # this is already 1 or 0
> sy = d0.month<7 ? d0.year, d0.year-1 # alternative form

Oh, were the parentheses situational? -0.5 on the form without
parentheses and with comma, then. IMO. And the ordering is Just Wrong.


I think the rest are pretty much just more of the same. Of course I
cotton to the form in general: I've written 'way too much C and C++
over the years *. The comma really doesn't seem adequate to the role
you give it; maybe that's for the same reasons.


*) didn't really use the ternary op all that often then, either. It's
one of those things you can live without, but it's sure handy to have
it around. I've been trying to think of something in uncontroversial
Python that feels about the same, and the best match I've come up with
is, well, it's a bit of an overstatement. But you know, now that we
have iterators (well, for some values of "us"), there's really no need
for the while statement anymore. It's redundant, just syntactic sugar
to replace

for dummy in infinite_iterator:
if inverted_condition:
break
... body of loop here...

winking'ly yours

Martin Maney

unread,
Feb 9, 2003, 6:39:51 PM2/9/03
to
Tim Peters <tim...@email.msn.com> wrote:

>> sy = d0.year - (1 if d0.month < 7 else 0)

> Me too, but note that it could be written (even in Python 1.0):


>
> sy = d0.year - (d0.month < 7)
>
> That bools are confusable with 0 and 1 in Python is A Feature.

Maybe, but I have never liked this sort of use. Been there, did that,
lived to regret it, eventually. The general lack of ugly, confusing
tricks like this is what I most like about Python. Well, that and the
batteries...

Tony Lownds

unread,
Feb 9, 2003, 11:34:24 PM2/9/03
to
[Tim Peters]
> [Martin Maney]
> > ...

> > Becomes, after a little rearrangement:
> >
> > sy = d0.year - (1 if d0.month < 7 else 0)
> >
> > I think this actually expresses the original logic a little more
> > clearly: the school year is the day's year unless the day's month is
> > January through June; then one must be subtracted to get the
calendar
> > year during which the school year began.
>
> Me too, but note that it could be written (even in Python 1.0):
>
> sy = d0.year - (d0.month < 7)
>
> That bools are confusable with 0 and 1 in Python is A Feature.

With the ?: syntax the rearrangement above becomes:

sy = d0.year - (d0.month < 7 ? 1 : 0)

And the refactoring you did becomes much more obvious.

For me, that a killer problem of PEP308's proposed syntax; with the
condition in the middle, reading *and* refactoring the code becomes
harder! That is why I cannot vote simply for PEP308.

The only syntaxes I'd like to see are:

condition "?" then-expr ":" else-expr

condition "?" then-expr "else" else-expr

I prefer ?: because:

- I liked it better after playing with ?: interactively[1]
- ":" balances "?" better than "else"
- consistent with the C-like language crowd, like python's operators
in
general.

One argument against ?: (yet another job for the colon) doesn't
convince
me. The three other places I see where colons are used are not likely
to
see ?: expressions in my opinion, and even then simply adding
parentheses
can restore readability:

- slicing/indexing: a[(t?x:y)]
- if statements: if (t?x:y):
- dictionary literals: {(t?x:y): value}

In real code ?: replaces three idioms. IMO ?: is more obvious than
using
and/or, more readable than (false, true)[condition], with better
semantics
than either idiom. The ?: syntax offers enough improvement to supplant
every
use of the aforementioned syntaxes in my python code.

That leaves this idiom:

if test:
lhs = then-expr
else:
lhs = else-expr

In some cases I think that kind of code is improved by using a
conditional
expression, especially when a complex lhs or common subexpression in
then-expr and else-expr can be factored out.

-Tony Lownds

[1] ESR has a patch to implement ?: that is easy to modify for current
CVS python
http://mail.python.org/pipermail/python-dev/2000-January/001883.html

Andrew Koenig

unread,
Feb 9, 2003, 11:52:11 PM2/9/03
to
Tony> With the ?: syntax the rearrangement above becomes:

Tony> sy = d0.year - (d0.month < 7 ? 1 : 0)

I'd prefer

sy = d0.month < 7? d0.year - 1: d0.year

despite duplicating d0.year because I would rather duplicate
d0.year than subtract 0 from it. But it's not a strong preference.

Tony> For me, that a killer problem of PEP308's proposed syntax; with the
Tony> condition in the middle, reading *and* refactoring the code becomes
Tony> harder! That is why I cannot vote simply for PEP308.

Tony> The only syntaxes I'd like to see are:

Tony> condition "?" then-expr ":" else-expr

Tony> condition "?" then-expr "else" else-expr

Why not

"if" condition: then-expr "else" ":" else-expr

?

--
Andrew Koenig, a...@research.att.com, http://www.research.att.com/info/ark

Andrew Dalke

unread,
Feb 10, 2003, 4:24:04 AM2/10/03
to
Martin Maney:

> Okay, a bleary-eyed survey of about 4000 lines of code from a project
> I've been working on in odd bits of time. Best Available Data, sir,
> but mine own. <wink>

Wow! Thank you for your effort!

If I may summarize:

Candidate 1 = maybe
Candidate 2 = no
Candidate 3 = yes
Candidate 4 = maybe
Candidate 5 = yes
Candidate 6 = maybe

BTW, I completely agree with your estimates of which are
good vs. maybe vs. bad uses of the if/else expression.

At most there are 6 changes in 4,000 lines of code, which is about
1 every 667. My estimate (based on an analysis of C/C++ code)
suggested numbers around 1,000 lines). Someone else's estimate
(my apologies, don't recall who) was about 1 in 200 lines, but I found
some problems in that estimate.

Assume the maybes are 50%s. That means there are about 3.5
proper uses of this in 40,000 LOC, or under 1 per 1,000 lines.
I interpret this to agree that it doesn't help much with overall
readability of Python code, since it won't be used all that often.

This assumes it will always be used when it is a better solution.
Not everyone will use the if/else expression. Some because they
don't like it, others because it isn't part of their toolchest, etc.
I looked at some C/C++ code and found a reasonable number of
examples where if/else was used when ?: could have been used.
I did not do a good survey of this, so I'll estimate it at 75% usage,
so I can be on the high side, and round things out to 3 uses in
40,000 lines of code.


Now consider that people will use if/else expression to make
things more complex than otherwise. There are 2.5 where it
could have been done, and I believe (as Bengt Richter was so
kind to point out ;) that some will do it.

(Earlier I listed some reasons: it's "tight" or "cool" or "terse",
or perhaps because "well, it's in the language so I'll use it" or
simply showing off.) My observations of misuse in C++ code
showed it was pretty high, so I'll assume 50% and round down
to 1 use in 40,000 LOC.

That means that for every 3 uses of the if/else expression which
make the code more readable/usable/maintainable, etc. then
we should expect 1 use which make it less so.

The numbers I came up with were closer to 1 to 1, but that's
because 1) I was working with a codebase written by people
who are not software engineers, and 2) your analysis does not
include inappropriate cases where you could have used a
if/else expression but were already using a better/more appropriate
Python construct.

(eg, using "x if x < y else y" instead of "min(x, y)")

I'm willing to concur from what I've seen from those who have done
analysis based on real-life code that

- if/else expression will be used well about once every 1,000 LOC

- for every 2 proper uses of the if/else expression there will be
1 improper use

Therefore, I am still against this PEP.

Andrew
da...@dalkescientific.com


Cameron Laird

unread,
Feb 10, 2003, 8:17:07 AM2/10/03
to
In article <mailman.1044781086...@python.org>,

No partial-wink disclaimers? Myself, I think casual maintainers
(and that *is* our target audience as Real-Life Programmers,
right?) will find
sy = d0.year
if d0.month < 7:
sy -= 1
best serves.
--

Cameron Laird <Cam...@Lairds.com>
Business: http://www.Phaseit.net
Personal: http://phaseit.net/claird/home.html

Kyler Laird

unread,
Feb 10, 2003, 12:49:15 PM2/10/03
to
cla...@lairds.com (Cameron Laird) writes:

>No partial-wink disclaimers? Myself, I think casual maintainers
>(and that *is* our target audience as Real-Life Programmers,
>right?) will find
> sy = d0.year
> if d0.month < 7:
> sy -= 1
>best serves.

Anyone want to claim that this is preferable for some?


if d0.month < 7:
sy = d0.year - 1
else:
sy = d0.year

I cringe at the duplication of "d0.year" but I've been
teaching Scheme recently and noticed that students seem
very comfortable saying "If this is the case, then the
answer is this, otherwise..." instead of "Always do this
and then if whatever, modify the result."

I'm not sure how I feel about it.

--kyler

Peter Hansen

unread,
Feb 10, 2003, 1:06:52 PM2/10/03
to

Speaking purely from a Test-Driven Development point of view,
that approach is *not* preferable because it involves
duplication (of d0.year in this case) whereas the original
form does not.

But I will certainly stand up and claim "this is preferable
for some"... just not for me. ;-)


-Peter

Andrew Koenig

unread,
Feb 10, 2003, 1:04:45 PM2/10/03
to
Here's an example from the Python 2.2.2 distribution, Lib/unittest.py,
lines 618-619:

self.stream.writeln("Ran %d test%s in %.3fs" %
(run, run == 1 and "" or "s", timeTaken))

Need I say more?

Tony Lownds

unread,
Feb 10, 2003, 2:25:34 PM2/10/03
to
Andrew Koenig <a...@research.att.com> wrote in message news:<yu99r8ag...@europa.research.att.com>...

> I'd prefer
>
> sy = d0.month < 7? d0.year - 1: d0.year
>
> despite duplicating d0.year because I would rather duplicate
> d0.year than subtract 0 from it. But it's not a strong preference.
>

Yes, that is a nice way of writing the expression.

> Tony> For me, that a killer problem of PEP308's proposed syntax; with the
> Tony> condition in the middle, reading *and* refactoring the code becomes
> Tony> harder! That is why I cannot vote simply for PEP308.
>
> Tony> The only syntaxes I'd like to see are:
>
> Tony> condition "?" then-expr ":" else-expr
>
> Tony> condition "?" then-expr "else" else-expr
>
> Why not
>
> "if" condition: then-expr "else" ":" else-expr
>
> ?

At first glance, I think C's syntax is more concise, consistent, and
does not confuse statements and expressions. Python's current idioms
for conditional expressions can be improved upon a bit, and IMO the ?:
syntax is an improvement. I'm not sure about the very statement-like
syntax above. At least it is in the right order! Is it even parsable?

Can you imagine explaining why this is good syntax:

if x: print y
else: print z

And this isn't:

if x: print x else: print y

-Tony Lownds

Andrew Koenig

unread,
Feb 10, 2003, 2:39:24 PM2/10/03
to
Tony>Tony> Can you imagine explaining why this is good syntax:

Tony> if x: print y
Tony> else: print z

Tony> And this isn't:

Tony> if x: print x else: print y

Anyone who wants to teach Python has to figure out how to explain it,
as this is the state of affairs today.

Aahz

unread,
Feb 10, 2003, 2:55:26 PM2/10/03
to
In article <yu99n0l4...@europa.research.att.com>,

Andrew Koenig <a...@research.att.com> wrote:
>
>Tony>Tony> Can you imagine explaining why this is good syntax:
>
>Tony> if x: print y
>Tony> else: print z
>
>Tony> And this isn't:
>
>Tony> if x: print x else: print y
>
>Anyone who wants to teach Python has to figure out how to explain it,
>as this is the state of affairs today.

That's half-true, in the context of this discussion. Adding an extra
step to explain why

print if x: x else: y

works is going to be a lot more difficult, IMO.
--
Aahz (aa...@pythoncraft.com) <*> http://www.pythoncraft.com/

Register for PyCon now! http://www.python.org/pycon/reg.html

Andrew Dalke

unread,
Feb 10, 2003, 3:44:37 PM2/10/03
to
Andrew Koenig:

> Here's an example from the Python 2.2.2 distribution, Lib/unittest.py,
> lines 618-619:
>
> self.stream.writeln("Ran %d test%s in %.3fs" %
> (run, run == 1 and "" or "s", timeTaken))
>
> Need I say more?

Care to make any comments about the use of the non-standard
and Pascal-like "writeln" instead of using the much more standard
"write" with a "\n" at the end of the string?

Are other parts of the code written as if by someone with
more experience in some language other than Python? Could that
experience have cause them to want a "?: by any means" rather
than using a more traditional approach?

Andrew
da...@dalkescientific.com


holger krekel

unread,
Feb 10, 2003, 2:01:34 PM2/10/03
to
Andrew Koenig wrote:
> Here's an example from the Python 2.2.2 distribution, Lib/unittest.py,
> lines 618-619:
>
> self.stream.writeln("Ran %d test%s in %.3fs" %
> (run, run == 1 and "" or "s", timeTaken))
>
> Need I say more?


No, but maybe you can replicate it some more :-)

I have seen worse effects of buggy code than this.
Besides, in a PEP-308 world you would certainly find the like of

self.stream.writeln("Ran %d test%s in %.3fs" %

(run, 's' if run==1 else '', timeTaken)

Getting things messed up with ternary ops (whichever) is easy enough.
That doesn't imply we have to introduce a new one.

holger

Andrew Koenig

unread,
Feb 10, 2003, 2:06:40 PM2/10/03
to
holger> I have seen worse effects of buggy code than this.
holger> Besides, in a PEP-308 world you would certainly find the like of

holger> self.stream.writeln("Ran %d test%s in %.3fs" %
holger> (run, 's' if run==1 else '', timeTaken)

holger> Getting things messed up with ternary ops (whichever) is easy enough.
holger> That doesn't imply we have to introduce a new one.

Indeed. That's part of the reason I now favor

self.stream.writeln("Ran %d test%s in %.3fs" %

(run, if run==1: "" else: "s", timeTaken)

because it doesn't look like anything new.

Anyway, the point that I consider important is that Python
programmers--including the authors of the Python library--consider an
if-then-else construct to be useful enough that they fake it.
Moreover, they do so in ways that are somtimes just plain wrong.

I think that if having a way to write an if-then-else expression is
a bad idea, then the and/or idiom is an even worse idea because it's
unreliable.

Roman Suzi

unread,
Feb 10, 2003, 3:53:26 PM2/10/03
to

I am sorry to observe that brain storm on good suggestion for "inline if"
failed. This clearly says that time has not come for inline ifs.


Sincerely yours, Roman Suzi
--
r...@onego.ru =\= My AI powered by Linux RedHat 7.3


Steve Holden

unread,
Feb 10, 2003, 5:17:01 PM2/10/03
to
"Andrew Koenig" <a...@research.att.com> wrote in message
news:mailman.1044904116...@python.org...

> holger> I have seen worse effects of buggy code than this.
> holger> Besides, in a PEP-308 world you would certainly find the like of
>
> holger> self.stream.writeln("Ran %d test%s in %.3fs" %
> holger> (run, 's' if run==1 else '', timeTaken)
>
> holger> Getting things messed up with ternary ops (whichever) is easy
enough.
> holger> That doesn't imply we have to introduce a new one.
>
> Indeed. That's part of the reason I now favor
>
>
> because it doesn't look like anything new.
>
However, it clearly introduces new precedence problems into the syntax: how
do I know you meant

self.stream.writeln("Ran %d test%s in %.3fs" %

(run, (if run==1: "" else: "s"), timeTaken)


and not (apart from the run-time error it would produce)

self.stream.writeln("Ran %d test%s in %.3fs" %

(run, if run==1: "" else: ("s", timeTaken))

Methinks anything that allows colons inside expressions will be tough for us
to read.

> Anyway, the point that I consider important is that Python
> programmers--including the authors of the Python library--consider an
> if-then-else construct to be useful enough that they fake it.
> Moreover, they do so in ways that are somtimes just plain wrong.
>

This isn;t the only area where people like to make things tougher for
themselves than they need really be. Some people would shoot themselves in
the foot even if they only had a pitchfork :-) (present company excluded,
naturally).

> I think that if having a way to write an if-then-else expression is
> a bad idea, then the and/or idiom is an even worse idea because it's
> unreliable.
>

I quite agree.

regards
--
Steve Holden http://www.holdenweb.com/
Python Web Programming http://pydish.holdenweb.com/pwp/

Samuele Pedroni

unread,
Feb 10, 2003, 5:27:03 PM2/10/03
to

"Steve Holden" <sho...@holdenweb.com> ha scritto nel messaggio
news:xxV1a.18264$qY4....@news2.central.cox.net...

> Methinks anything that allows colons inside expressions will be tough for
us
> to read.

I agree (and lambda: does not count as counterexample).


Andrew Koenig

unread,
Feb 10, 2003, 5:40:44 PM2/10/03
to
Steve> However, it clearly introduces new precedence problems into the
Steve> syntax: how do I know you meant

Steve> self.stream.writeln("Ran %d test%s in %.3fs" %
Steve> (run, (if run==1: "" else: "s"), timeTaken)

Steve> and not (apart from the run-time error it would produce)

Steve> self.stream.writeln("Ran %d test%s in %.3fs" %
Steve> (run, if run==1: "" else: ("s", timeTaken))

Steve> Methinks anything that allows colons inside expressions will be
Steve> tough for us to read.

I'm not introducing any new precedence problems.

You know which of the alternatives above I mean in the same way you know that

foo(lambda x, y: x, y)

means

foo((lambda x, y: x), y)

and not

foo(lambda x, y: (x, y))

You can like or dislike the existing rules for colons inside expressions,
but I'm not proposing to change them.

holger krekel

unread,
Feb 10, 2003, 4:43:44 PM2/10/03
to

good questions although your prename-cousin does have a point.
OTHOH nobody questioned that it's quite possible to mess up today's
"ternary op". They are inherently messy IMO and so would
the bugs we encounter in a PEP-308-world be. Let's stay binary
or even unary as much as possible.

Maybe the voting should be accompanied by pleadings titled
"Andrew versus Andrew" :-)

holger

David Eppstein

unread,
Feb 10, 2003, 6:48:32 PM2/10/03
to
In article <3e4828b6$1...@news.bluewin.ch>,
"Samuele Pedroni" <pedr...@bluewin.ch> wrote:

> > Methinks anything that allows colons inside expressions will be
> > tough for us to read.
>
> I agree (and lambda: does not count as counterexample).

But do slices count?

--
David Eppstein UC Irvine Dept. of Information & Computer Science
epps...@ics.uci.edu http://www.ics.uci.edu/~eppstein/

Samuele Pedroni

unread,
Feb 10, 2003, 6:55:43 PM2/10/03
to

"David Eppstein" <epps...@ics.uci.edu> ha scritto nel messaggio
news:eppstein-2FA2BF...@news.service.uci.edu...

> In article <3e4828b6$1...@news.bluewin.ch>,
> "Samuele Pedroni" <pedr...@bluewin.ch> wrote:
>
> > > Methinks anything that allows colons inside expressions will be
> > > tough for us to read.
> >
> > I agree (and lambda: does not count as counterexample).
>
> But do slices count?
>

as much as : in { "a": 2 }, so no.

But I like how much effort is putting the pro-camp to make me vote no, not
yes <wink>.


Erik Max Francis

unread,
Feb 10, 2003, 8:56:30 PM2/10/03
to
Roman Suzi wrote:

> I am sorry to observe that brain storm on good suggestion for "inline
> if"
> failed. This clearly says that time has not come for inline ifs.

Whose brainstorm? Yours?

There has actually been a substantial amount of agreement in the pro-PEP
camp. Lots of them thought x if C else y was acceptable; lots also
thought if C: x else: y was acceptable.

100% of the pro-PEP people haven't agreed 100% on one form, but that
hardly means that the brainstorm "failed" or that therefore the
conditional operator's "time has not come."

Why don't you save the BDFL decisions for the actual BDFL?

--
Erik Max Francis / m...@alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE
/ \ Whoever contends with the great sheds his own blood.
\__/ Sa'di
Polly Wanna Cracka? / http://www.pollywannacracka.com/
The Internet resource for interracial relationships.

James J. Besemer

unread,
Feb 10, 2003, 9:32:30 PM2/10/03
to

Steve Holden wrote:


> However, it clearly introduces new precedence problems into the syntax:

Not a problem. You simply evidently didn't fully understand the proposal as
Andrew specified it in the grammar.

> how do I know you meant
>

> (run, (if run==1: "" else: "s"), timeTaken)
>
>
> and not (apart from the run-time error it would produce)
>

> (run, if run==1: "" else: ("s", timeTaken))
>

The former would apply and you know this because the new if constuct binds at
a similar level as the "or" operator. Actually, relative to ",", if/else is
similar to "+", so it's the same rationale for which

( run, test + "s", timeTaken )

would never mean

( run, test + ("s", timeTaken ))

Actually, "," is comparatively so low priority, so they break up just about
anything expression-based.

When you think about it, this all is fairly intuitive.

--jb

--
James J. Besemer 503-280-0838 voice
2727 NE Skidmore St. 503-280-0375 fax
Portland, Oregon 97211-6557 mailto:j...@cascade-sys.com
http://cascade-sys.com

Erik Max Francis

unread,
Feb 10, 2003, 10:58:45 PM2/10/03
to
Andrew Dalke wrote:

> Andrew Koenig:
>
> > Here's an example from the Python 2.2.2 distribution,
> > Lib/unittest.py,
> > lines 618-619:
> >
> > self.stream.writeln("Ran %d test%s in %.3fs" %
> > (run, run == 1 and "" or "s", timeTaken))
> >
> > Need I say more?
>
> Care to make any comments about the use of the non-standard
> and Pascal-like "writeln" instead of using the much more standard
> "write" with a "\n" at the end of the string?

That's a stylistic issue. We're talking about a _bug_ that someone
introduce because they trusted a conditional operator-like idiom too
much.

> Are other parts of the code written as if by someone with
> more experience in some language other than Python? Could that
> experience have cause them to want a "?: by any means" rather
> than using a more traditional approach?

The point here is that this validates what Andrew and others (including
myself) have been saying all along: People want a conditional operator
bad enough that they use pale comparisons, and those comparisons have
flaws. People who use the `C and x or y' idiom may do so without
understanding those limitations, and that will lead to bugs.

Here he has proof of this not just theoretically, not just in random
code in the world, but in the standard library itself!

--
Erik Max Francis / m...@alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE

/ \ Ride / Ride this wave of mine
\__/ Res
Esperanto reference / http://www.alcyone.com/max/lang/esperanto/
An Esperanto reference for English speakers.

Martin Maney

unread,
Feb 10, 2003, 11:16:14 PM2/10/03
to
Aahz <aa...@pythoncraft.com> wrote:
> That's half-true, in the context of this discussion. Adding an extra
> step to explain why
>
> print if x: x else: y
>
> works is going to be a lot more difficult, IMO.

Well, yes, since that's not the PEP syntax.

print x if x else y

doesn't seem to me to present any serious problems. :-)

So is it that you call him BDFL because he blushes when you say
"genius"? That syntax looks better every time I write it, but I really
though it was a Norwegian Blue when I first saw it.

Martin Maney

unread,
Feb 10, 2003, 11:35:37 PM2/10/03
to
Kyler Laird <Ky...@news.lairds.org> wrote:
> Anyone want to claim that this is preferable for some?
> if d0.month < 7:
> sy = d0.year - 1
> else:
> sy = d0.year

Well, since that was in fact how I wrote it... <wink>

> I cringe at the duplication of "d0.year" but I've been
> teaching Scheme recently and noticed that students seem
> very comfortable saying "If this is the case, then the
> answer is this, otherwise..." instead of "Always do this
> and then if whatever, modify the result."

It reads the way we think, at least in English. It takes years of
experience to learn to think of it in mercilessly refactored until
there's no redundancy left form, and then more years to see the
foolishness of pushing it that far in every case.

BTW, I wanted to say somewhere in this thread that I'm not at all sure
whether I'd choose to write *any* of these candidates using the ternary
form. The "sep" example is probably the most likely one, assuming it
was actually written with only a single use of "sep". I suspect it
used to be used at least twice in an earlier version.

I know that this would be useful for lambdas, but I seem to have
rewritten all such uses (or maybe overlooked them - I wasn't
specifically looking for that sort of thing, alas). That's one flaw in
this survey: it's on a body of code that has mostly been rewritten
(well, heavily refactored, anyway) at least once... by someone who
loathes the existing kluges enough that I very likely tried them and
got rid of them... probably back in August/September, when I was
excited about some of that stuff from having just read the Cookbook. I
know a fair number of lambdas vanished as list comprehensions came into
vogue here!

I *know* I have had to write a function for things that would be
trivial inline lambdas with the PEP extension, but they're all gone
now. So the candidates I found are probably all near-misses int he
first place.

It's not easy to find good existing examples for a language feature
that doesn't exist!

Roman Suzi

unread,
Feb 11, 2003, 12:17:15 AM2/11/03
to
On Mon, 10 Feb 2003, Erik Max Francis wrote:

>Roman Suzi wrote:
>
>> I am sorry to observe that brain storm on good suggestion for "inline
>> if"
>> failed. This clearly says that time has not come for inline ifs.
>
>Whose brainstorm? Yours?
>
>There has actually been a substantial amount of agreement in the pro-PEP
>camp. Lots of them thought x if C else y was acceptable; lots also
>thought if C: x else: y was acceptable.

>100% of the pro-PEP people haven't agreed 100% on one form, but that
>hardly means that the brainstorm "failed" or that therefore the
>conditional operator's "time has not come."
>
>Why don't you save the BDFL decisions for the actual BDFL?

I do not decide for the BDFL. I've decided for myself. I see no reason to
contribute to PEP 308 as I am convinced inline if doesn't belong to Python, as
all proposed forms are much less than optimal. Next hope for inline if is lazy
evaluation (if it ever to be added to Python): then everybody will be able to
add "if" as a function treating it's arguments specially. But I do not believe
BDFL will ever add such function to Python, as it means more confusion. Even
more likely "implicit lambda" proposal:

ifelse(cond, :YES, :NO)

== ifelse(cond, lambda: YES, lambda: NO)

will not probably be accepted... Anybody up to the PEP?

Delaney, Timothy C (Timothy)

unread,
Feb 11, 2003, 12:36:10 AM2/11/03
to
> From: Tony Lownds [mailto:tony...@lownds.com]

>
> Can you imagine explaining why this is good syntax:
>
> if x: print y
> else: print z
>
> And this isn't:
>
> if x: print x else: print y

Nope. I will of course explain why *both* are bad style.

Tim Delaney

Delaney, Timothy C (Timothy)

unread,
Feb 11, 2003, 12:32:35 AM2/11/03
to
> From: Andrew Koenig [mailto:a...@research.att.com]
>
> Tony> With the ?: syntax the rearrangement above becomes:
>
> Tony> sy = d0.year - (d0.month < 7 ? 1 : 0)

>
> I'd prefer
>
> sy = d0.month < 7? d0.year - 1: d0.year
>
> despite duplicating d0.year because I would rather duplicate
> d0.year than subtract 0 from it. But it's not a strong preference.

And I would strongly prefer

sy = d0.year

if d0.month < 7:
sy -= 1

which is extremely easy to read, and fits in my field of vision completely (unlike either of the above alternatives where I have to scan horizontally).

Tim Delaney

Erik Max Francis

unread,
Feb 11, 2003, 3:19:38 AM2/11/03
to
Roman Suzi wrote:

> I do not decide for the BDFL. I've decided for myself. I see no reason
> to
> contribute to PEP 308 as I am convinced inline if doesn't belong to
> Python, as
> all proposed forms are much less than optimal.

Correct me if I'm wrong, but haven't you been against the addition of a
conditional operator from the very beginning? If so, is this meant to
be some sort of revelation?

--
Erik Max Francis / m...@alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE

/ \ I always entertain great hopes.
\__/ Robert Frost
REALpolitik / http://www.realpolitik.com/
Get your own customized newsfeed online in realtime ... for free!

Erik Max Francis

unread,
Feb 11, 2003, 3:46:37 AM2/11/03
to
Martin Maney wrote:

> Aahz <aa...@pythoncraft.com> wrote:
>
> > print if x: x else: y
>

> Well, yes, since that's not the PEP syntax.

It is now. Check the PEP on the python.org Web site.

Roman Suzi

unread,
Feb 11, 2003, 3:34:33 AM2/11/03
to
On Tue, 11 Feb 2003, Erik Max Francis wrote:

> Roman Suzi wrote:
>
> > I do not decide for the BDFL. I've decided for myself. I see no reason
> > to
> > contribute to PEP 308 as I am convinced inline if doesn't belong to
> > Python, as
> > all proposed forms are much less than optimal.
>
> Correct me if I'm wrong, but haven't you been against the addition of a
> conditional operator from the very beginning? If so, is this meant to
> be some sort of revelation?

I was against inline if from the beginning, however, I hoped to see some
nice appleaing syntax for it and even proposed some variants. But now I
see it is failing: nobody came with good proposal, IMHO.


Sincerely yours, Roman A.Suzi
--
- Petrozavodsk - Karelia - Russia - mailto:r...@onego.ru -


Erik Max Francis

unread,
Feb 11, 2003, 4:32:23 AM2/11/03
to
Roman Suzi wrote:

> I was against inline if from the beginning, however, I hoped to see
> some
> nice appleaing syntax for it and even proposed some variants. But now
> I
> see it is failing: nobody came with good proposal, IMHO.

It hasn't failed until we vote. All I hear you saying is, "I vote no."

By no means do I mean to suggest that it's not appropriate for you to
vote no, nor for you to publicly state that you intend to vote no, but
it seems a little like disinformation to start a new thread suggesting
that the PEP has failed when all you really meant to say is that you
intend to vote against it.

Michele Simionato

unread,
Feb 11, 2003, 12:14:43 PM2/11/03
to
"Samuele Pedroni" <pedr...@bluewin.ch> wrote in message news:<3e4828b6$1...@news.bluewin.ch>...

+1

Michele

Paul Rubin

unread,
Feb 11, 2003, 7:23:12 PM2/11/03
to
Martin Maney <ma...@pobox.com> writes:
> These are the uses of a simple if/else that seemed to me to be at least
> vaguely suitable for the proposed ternary operator; most of the if/else
> occurences rejected were over four lines or had very little in common
> between the if and the else code. I don't believe I omitted any that
> weren't less good candidates than the ones below.

I think occurrences of

x = foo # set default value
if cond:
x = bar

should also count as potential places for a conditional expression,
even though no "else" is involved. It's a shortcut for

if cond: x = bar
else: x = foo

and so instances of it should be included in your "database".

0 new messages