To: pep30...@hotmail.com
Subject: PEP308
From: <valid email address>
Line 1: <letter of most preferred format> <accept or reject> <format>
Line 2: <letter of second best format> <accept or reject> <format>
Line 3: <letter of third best format> <accept or reject> <format>
Line 4: <full name of voter>
Line 5: <example 1>
Line 6: <example 2>
Line 7: <example 3>
Line 8: <example 4>
Line 9: <example 5>
Every line is required.
The published results will only include lines 1, 2, 3, and 4.
Note, that means your name is published.
You can use a fake name but a real name is preferred.
The email address is used for:
assuring only one vote per address.
notification of an improperly formatted ballot.
resolving any questions that arise about the vote process.
Write-out these five examples using your most preferred syntax:
x = "door" + (if quantity>1: "s" else: "")
data = (if hasattr(s, 'open'): s.readlines() else: s.split())
z = 1.0 + (if abs(z) < .0001: 0 else: z)
t = v[index] = (if t<=0: t-1.0 else: -sigma /(t + 1.0))
return (if len(s)<10: insertsort(s) else: quicksort(s))
Note, the examples are required but will not be used.
Try to get them right, but it is okay if they are wrong.
Marking accept means that you prefer this format over no-change.
Marking reject means that you prefer no-change, but if there is
one, then the marked choice would be the best one.
CHOICES (taken from Erik Max Francis's posting of seconded choices)
-------
A. x if C else y
B. if C then x else y
C. (if C: x else: y)
D. C ? x : y
E. C ? x ! y
F. cond(C, x, y)
G. C ?? x || y
H. C then x else y
I. x when C else y
J. C ? x else y
K. C -> x else y
L. C -> (x, y)
M. [x if C else y]
N. ifelse C: x else y
O. <if C then x else y>
P. C and x else y
Q. any write-in vote
Note 1: All of these options have short-circuit behavior.
That means that cond(C,x,y) would be a special syntax.
Note 2: All options are eligible. If the PEP notes that a proposal
had been rejected at some point, then consider it revived.
SAMPLE BALLOT
-------------
C accept (if c: x else: y)
D reject c ? a : b
H reject c then a else b
John Jones
x = "door" + (if quantity>1: "s" else: "")
data = (if hasattr(s, 'open'): s.readlines() else: s.split())
z = 1.0 + (if abs(z) < .0001: 0 else: z)
t = v[index] = (if t<=0: t-1.0 else: -sigma /(t + 1.0))
return (if len(s)<10: linsort(s) else: qsort(s))
RATIONALE AND PROCESS
---------------------
In the end, only Guido's vote counts. The purpose of the voting is
to provide him with information about how the community feels.
The goal of collecting preferences along with accept/rejects is to
allow everyone (including those who prefer the status quo) to
also be able to express which syntax they find least objectionable.
The end result is that Guido will know which is the most preferred
syntax AND the how much it is preferred to the status quo.
The purpose of publishing both names and the votes is to provide
assurance that the process is honest. Also, I think that people
are more careful in their voting if they publicly take a position.
However, if someone wants to vote in secret, they are welcome to
use a pseudonym; at least, they will see their chosen name on the
tally and know their vote was counted.
The purpose of the examples section is voter education. This
provides some assurance that each voter has at least tried
their own preferred syntax.
EXCEPTION HANDLING
------------------
If there is a dispute, I'll ask Laura Creighton to resolve it.
Her decision will be final.
If I messed-up the ballot, I will repost a correction.
If the email account fails, I will open a new one and extend
the voting by a day.
If you make a mistake or change your mind, you may re-submit
your vote and the previous vote will be thrown out.
If there are any questions or discussion, please use the newsgroup.
The email address listed above is only for ballots.
Vote Early. Vote Once.
Raymond Hettinger
> If there are any questions or discussion, please use the newsgroup.
> The email address listed above is only for ballots.
Um, wasn't there general agreement on both sides that purposes would be
best served by voting on each alternative separately, including an
option for "no change"? The debate seemed to be about whether the
process should involve yes/no voting for each entry or yes/no/abstain.
For instance, there are more than three forms I'd _accept_ (in terms of
being willing to tolerate), but there are fewer than three I'd
affirmatively vote for, and there are more than three I'd decidedly vote
against. If one has to pick only three and vote to accept or decline
them, this doesn't give the opportunity to really express one's opinion
of each choice ("These I'd like, these I'd tolerate, these I wouldn't
like").
Is this vote blessed by Guido, or is it a unilateral action? Someone
else was claiming that they were going to be holding the vote up tp this
point.
--
Erik Max Francis / m...@alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE
/ \ Virtue has never been as respectable as money.
\__/ Mark Twain
Python chess module / http://www.alcyone.com/pyos/chess/
A chess game adjudicator in Python.
Couldn't a real address be registered? ;)
> Subject: PEP308
> From: <valid email address>
I assume those are the e-mail headers, the rest is content?
> Line 1: <letter of most preferred format> <accept or reject> <format>
> Line 2: <letter of second best format> <accept or reject> <format>
> Line 3: <letter of third best format> <accept or reject> <format>
> Line 4: <full name of voter>
> Line 5: <example 1>
> Line 6: <example 2>
> Line 7: <example 3>
> Line 8: <example 4>
> Line 9: <example 5>
>
> Every line is required.
What happens on a syntax/format error?
> CHOICES (taken from Erik Max Francis's posting of seconded choices)
(...)
> Q. any write-in vote
What does Q mean? Can I still select a non-seconded choice?
> SAMPLE BALLOT
> -------------
> C accept (if c: x else: y)
> D reject c ? a : b
> H reject c then a else b
Is c case sensitive? Above, C was capitalized, is a lowercase c
accpepted?
> If you make a mistake or change your mind, you may re-submit
> your vote and the previous vote will be thrown out.
...but am I notified if I make a format or syntax mistake?
> If there are any questions or discussion, please use the newsgroup.
> The email address listed above is only for ballots.
yours,
Gerrit.
--
Asperger Syndroom - een persoonlijke benadering:
http://people.nl.linux.org/~gerrit/
Het zijn tijden om je zelf met politiek te bemoeien:
http://www.sp.nl/
Yes.
> What happens on a syntax/format error?
I reply to email saying that the vote needs to be resent..
> > Q. any write-in vote
>
> What does Q mean? Can I still select a non-seconded choice?
You can select anything. Q is there in-case your favorite
isn't on the list.
> Is c case sensitive? Above, C was capitalized, is a lowercase c
> accpepted?
Yes.
> > If you make a mistake or change your mind, you may re-submit
> > your vote and the previous vote will be thrown out.
>
> ...but am I notified if I make a format or syntax mistake?
Yes.
Raymond Hettinger
It's a simple thing. State the top three preferences and mark whether
each should be preferred to no-change. Guido is smart enough to
interpret the results.
If over a hundred posts weren't sufficient to express an opinion, by all
means, submit a vote in any format and I'll attach it to the results. There
is no need to leave anyone feeling angry and unheard. After all, it is
basically an opinion survey so Guido can get a sense of how the
community is leaning.
>Someone
> else was claiming that they were going to be holding the vote up tp this
> point.
That person sufferred much negativity here and no longer has the time
or inclination, so he passed the torch to me. Hopefully, I'll be treated
better. I'm volunteering the time to tally the results and then Guido
will make the call.
Raymond Hettinger
> Note, the examples are required but will not be used.
> Try to get them right, but it is okay if they are wrong.
If they're not used, and can be wrong, what on *earth* are they for?
It seems to me this serves no good purpose except making voting more
difficult than it needs to be -- particularly for "no to any form of
ternary" voters.
My apologies if this has already been well-discussed, I did not have the
stamina to follow the PEP308 threads after the first few days of discussion.
But I really did expect voting to be simpler and more direct than this!
--
James Kew
jame...@btinternet.com
-Dagur
Raymond's original mail states:
> The purpose of the examples section is voter education. This
> provides some assurance that each voter has at least tried
> their own preferred syntax.
Although it's true that if one rejects all, it's strange to have
to do this.
yours,
gerrit.
Ah -- yes, so it does. My apologies.
--
James Kew
jame...@btinternet.com
> BASICS
> ------
> Vote by email no later than Noon (EST) on Sunday, March 9, 2003.
> Use the following format:
>
> To: pep30...@hotmail.com
> Subject: PEP308
> From: <valid email address>
> Line 1: <letter of most preferred format> <accept or reject> <format>
> Line 2: <letter of second best format> <accept or reject> <format>
> Line 3: <letter of third best format> <accept or reject> <format>
> Line 4: <full name of voter>
> Line 5: <example 1>
> Line 6: <example 2>
> Line 7: <example 3>
> Line 8: <example 4>
> Line 9: <example 5>
>
> Every line is required.
I'm in favour of no ternary, and I can't think of 3 options I'd be
willing to have if one was forced on me (so I can't fill in lines 1-3
- I can do 2 lines, but not a third).
I don't feel this is unreasonable - if a ternary was introduced, I
simply wouldn't use it at all (my 2 votes of "reject" mean that I
might be willing to use, or at least maintain code which used, these 2
forms, in certain circumstances).
Can we allow less than 3 vote lines, please? Or have some other way of
not being forced to pick 3.
> Write-out these five examples using your most preferred syntax:
> x = "door" + (if quantity>1: "s" else: "")
> data = (if hasattr(s, 'open'): s.readlines() else: s.split())
> z = 1.0 + (if abs(z) < .0001: 0 else: z)
> t = v[index] = (if t<=0: t-1.0 else: -sigma /(t + 1.0))
> return (if len(s)<10: insertsort(s) else: quicksort(s))
> Note, the examples are required but will not be used.
> Try to get them right, but it is okay if they are wrong.
As I don't have a "preferred syntax", this was an interesting
exercise, trying to write these using my least disliked syntax - it
confirmed to me that I'd write *all* of the examples as something
other than onel-liners.
> RATIONALE AND PROCESS
> ---------------------
> In the end, only Guido's vote counts. The purpose of the voting is
> to provide him with information about how the community feels.
In which case, how are the votes going to be summarised for him? I
assume you're not going to ask him to read all of the voting mails and
work out the implications himself?
> The goal of collecting preferences along with accept/rejects is to
> allow everyone (including those who prefer the status quo) to
> also be able to express which syntax they find least objectionable.
> The end result is that Guido will know which is the most preferred
> syntax AND the how much it is preferred to the status quo.
Um. I can't see how this will work - can you explain how the
summarising will be done? (Sorry, I have little experience with
multiple-choice voting schemes like this).
> The purpose of the examples section is voter education. This
> provides some assurance that each voter has at least tried
> their own preferred syntax.
OK, I tried my "preferred" syntax. I didn't like it :-)
> If you make a mistake or change your mind, you may re-submit
> your vote and the previous vote will be thrown out.
For now, I've submitted a vote with a deliberately invalid line
3. I'll submit a correction if (when) you clarify how to not express a
"3rd place" fallback preference.
Paul.
--
This signature intentionally left blank
I really didn't want to be caught up with this (meta meta) discussion,
but I do not think this voting procedure takes people like me
into account.
Anyway, why it turned out this way is very explainable. The people who
liked the debates about ternary operators and liked to weigh them against
each other are the ones who designed the voting procedure, as they care.
This results in an overly complicated procedure that those who *don't*
care about ternary operators won't understand very well.
Raymond Hettinger <pep30...@hotmail.com> wrote:
> Marking accept means that you prefer this format over no-change.
> Marking reject means that you prefer no-change, but if there is
> one, then the marked choice would be the best one.
Hm..my interpretation of this is:
This voting procedure is has been designed by those with an interest
in the adoption of a ternary operator. People who do not care about a
ternary operator will still have to examine ternary operators to pick their
preferences. They still have to understand this rather complicated voting
procedure and list examples.
They need to understand that if they reject something they need to
reject their most favored choice, even though they don't favor any of them.
I think. I'm not sure what this all means.
Anyway, this is not an election for representatives, where I need *a*
representative at all. In that case the option 'none of the above' makes
less sense (though should still be supplied as it can indicate a message
about the whole system). In this case it's however perfectly feasible
to be happy without a ternary operator and to say "I just plain don't want
to consider any".
[snip]
> The end result is that Guido will know which is the most preferred
> syntax AND the how much it is preferred to the status quo.
No it won't. People like me who did not bother to follow the discussion much
as they did not care about a ternary operator and did not want to consider
it much are faced with a rather complicated set of procedures to go to
in order to vote against any change in this regard at all. I still don't
really know what I should do..
Should I really need to figure out which of the options I
dislike *least* and then give examples of them? And then reject them?
Why do I need to put in all that effort when I just don't want any of them?
Perhaps some people were rather focused on the PEP 308 discussions and thinks
everybody voting wants to be caught up in them as well? Now I basically
have to end up picking some from a list of ternary operator candidates,
and then reject them, right? How are people who don't bother to spend
this much time trying to figure it out going to figure it out?
Am I missing something here?
> EXCEPTION HANDLING
> ------------------
> If there is a dispute, I'll ask Laura Creighton to resolve it.
> Her decision will be final.
Laura, please help those of us who do not particularly want a
ternary operator in Python and do not want to be educated in that
respect, and still want to put in a vote if only they could figure
out a sensible way to do so.
Though I hope I'm just missing something here..
Regards,
Martijn
--
History of the 20th Century: WW1, WW2, WW3?
No, WWW -- Could we be going in the right direction?
Here's how mine looks:
X reject (whatever)
Y reject (whatever)
Z reject (whatever)
Donn Cave
N/A
N/A
N/A
N/A
N/A
Do you see any ambiguity?
I'd be more concerned that no one is paying attention by now.
The debate over which solution is better for this non-problem
has been so thoroughly uninteresting that some have probably
explicitly filtered it, along with one or two of the most
prolific posters, and the rest of us have gotten used to seeing
"PEP 308" as background noise.
Donn Cave, do...@drizzle.com
>Should I really need to figure out which of the options I
>dislike *least* and then give examples of them? And then reject them?
>Why do I need to put in all that effort when I just don't want any of them?
>Perhaps some people were rather focused on the PEP 308 discussions and thinks
>everybody voting wants to be caught up in them as well? Now I basically
>have to end up picking some from a list of ternary operator candidates,
>and then reject them, right? How are people who don't bother to spend
>this much time trying to figure it out going to figure it out?
Hmm, there was the Q option (fill-in). So if nothing else, you can always
come up with 3 randomly horrendous syntaxes, and then reject those three.
Of course, you also have to just how horrendous you syntax is...
/Anders
--
-- Of course I'm crazy, but that doesn't mean I'm wrong.
Anders Hammarquist | i...@cd.chalmers.se
Physics student, Chalmers University of Technology, | Hem: +46 31 88 48 50
G|teborg, Sweden. RADIO: SM6XMM and N2JGL | Mob: +46 707 27 86 87
Here's mine:
--begin of voting message--
A...Q rejected #line 1
A...Q rejected #line 2
A...Q rejected #line 3
Gerrit Muller # line 4
#line 5
#line 6
#line 7
#line 8
#line 9
## I have never experienced the need for a ternary operator, so I would not
make the language any more bloated/heavy by adding it, even if the addition
is small.
--end of voting message--
Perhaps Raymond will specify otherwise, but it seems to me that if you
wish to vote to reject the introduction of any ternary operator, you
could fill out the following:
Q reject NONE
Q reject NONE
Q reject NONE
Voter Name
NONE
NONE
NONE
NONE
NONE
That seems to meet all the rules. Of course, I guess this leaves the
danger that a new ternary expression spelled "NONE" (for every C, x, y)
will be added to Python :-).
Yours, Lulu...
You could, e.g., vote for these:
E. C ? x ! y
F. cond(C, x, y)
O. <if C then x else y>
IOW, vote for ones you know Guido wouldn't accept on his most feverish day.
If everyone who wants no change did that, and there are a lot of them, Guido
will conclude that the community is hopeless and give up in disgust <0.9
wink>.
The thing that is missing from the voting procedure is an explicit way
to vote for no change. I guess if we could all read Guido's mind, your
way might acheive the same effect but I would prefer that some explicit
and unambiguous way to vote for no change (i.e., no ternary expression
syntax addition) be built into the voting mechanism. We've seen several
methods illustrated in postings, but it isn't clear, at least to me,
that any of them are assured to not be reject as invalid votes or if
accepted as valid votes, that the intended effect is achieved. My
ballot was
[A-Q] reject (anything)
[A-Q] reject (anything)
[A-Q] reject (anything)
Rod Haper
Gack!
Gack!
Gack!
Gack!
Gack!
So, how about it Raymond and Laura? Is my ballot a valid vote for no
addition of a ternay expression syntax? If not, what's the approved
solution?
--
Rod
+----------------------------------+
| There is a better way ... |
| LAP => Linux + Ada95 + Python |
+----------------------------------+
Q reject NONE
Q reject NONE
Q reject NONE
Dennis Reinhardt
n/a
n/a
n/a
n/a
n/a
------
308 represents too much cruft. Most examples look good as one-liners with
short names. They do not look so good with longer names. Here is an
example:
z_of_useful_length = 1.0 + (if abs(z_of_useful_length) < .0001: 0 else:
z_of_useful_length)
The above long-name can be expressed in current Python in nearly the same
number of characters as
if abs(z_of_useful_length) < .0001:
z_of_useful_length = 1.0
else:
z_of_useful_length += 1.0
... much more readable.
--
Dennis Reinhardt
http://www.spamai.com
No.
I do however see a lot of work being done on something that ought to be
simple. So everyone who doesn't wants no ternary operator and has no
opinion on the ones offered for consideration has to figure out
somehow that this is the way to vote? Seems rather discouraging to me.
The whole procedure seems set up to get a tally on which is the
better solution, not on whether we need a solution at all, and it's
positive discouraging to actually figure out how to vote for that.
(rejecting the ones you like best is still pretty weird to me.. or
rejecting non existent entries..)
> I'd be more concerned that no one is paying attention by now.
> The debate over which solution is better for this non-problem
> has been so thoroughly uninteresting that some have probably
> explicitly filtered it, along with one or two of the most
> prolific posters, and the rest of us have gotten used to seeing
> "PEP 308" as background noise.
Yes, that's likely the case. This one only caught me by coincidence
and also because I'd been watching out for an actual start of voting,
but not everybody will do this. And of course the newsgroup is already
a very self selecting audience (but that's who Guido consulted).
Heh. :)
Anyway, my basic point remains; I've seen a bunch of creative answers on
how to just vote against any such operator, but I think I've seen 4 different
ones, and I don't think one should need to be that persistent and creative
just in order to vote no.
the votes can be easely intepreted this way:
X reject; Y reject; Z reject
means
prefer NO-CHANGE over X which is preferred over Y which is preferred over Z
... over anything else
X accept; Y reject; Z reject
prefer X over NO-CHANGE over Y over Z over anything else
X accept; Y accept; Y reject
prefer X over Y over NO-CHANGE over Z over anything else
The problematic kind of vote is:
X accept; Y accept; Z accept
because you can't infer their opinion wrt WEIRD different from X,Y,Z and
NO-CHANGE. Do they want a ternary so badly such that WEIRD is preferred over
NO-CHANGE?
The *real* danger, though, is that a ternary operator will end up
being added and your voice (as far as your preference for which
ternary operator add if one must be added) will be unheard.
Jeremy
I think it is too bad a nested example wasn't required. If the
ternary operator is added, and Python continues relentless world
domination ;-) , I will probably have to puzzle out somebody's
unfortunate nested ternary operator expression... at least once in my
life.
This might give even the most rabid supporter pause.
>SAMPLE BALLOT
>-------------
>C accept (if c: x else: y)
>D reject c ? a : b
>H reject c then a else b
>John Jones
>x = "door" + (if quantity>1: "s" else: "")
>data = (if hasattr(s, 'open'): s.readlines() else: s.split())
>z = 1.0 + (if abs(z) < .0001: 0 else: z)
>t = v[index] = (if t<=0: t-1.0 else: -sigma /(t + 1.0))
>return (if len(s)<10: linsort(s) else: qsort(s))
It is also too bad that examples of how to helpfully reject all
ternary operator forms were not given.
There would be 2 cases of rejecting the ternary operator:
1. Horrified, but still able to rank 3 in order of least offense.
(These would be people who have been steeled by voting in recent
US presidential elections...)
These voters could follow the format of lines 1 through 4, but be
spared typing the examples.
2. Horrified, and reduced to Lovecraftian psychic jelly by all
ternary operator syntax.
These voters could compose obscene ASCII art to express the full
measure of their contempt and disgust.
Or use the single word 'REJECT', perhaps punctuated by writing the
5 examples in proper old-fasioned Python.
>Vote Early. Vote Once.
Mr. Raymond Hettinger must not be from Chicago.
Manuel
I actually switched my top two preferences after trying them out. So,
good idea.
TJR
The voting procedure seems to insist that to have a say in the matter,
one really has to have a positive preference in order to make a real
difference - one can't say "I reject all this armchair language design
and await the day when I can read comp.lang.python without having to
filter out 10000 messages about frivolous wishlist items".
In order to represent the wishes of those rendered silent, I suggest
the appointment of the four horsemen of the apocalypse as
adjudicators. Upon completion of the voting procedure, the community
will await the arrival of the four horsemen (possibly arriving
straight from a well-deserved skiing trip in hell) who will then judge
the most popular ternary forms on the basis of "whole community
momentum" before delivering their recommendation to the BDFL.
Paul
> Write-out these five examples using your most preferred syntax:
> x = "door" + (if quantity>1: "s" else: "")
Resulting in "You have opened 0 door"? So maybe that should be
'quantity != 1'. Also, what if you change 'door' to a word where
adding a traling 's' doesn't make the plural, or translate to a
language where it never does? This would be better (IMHO):
x = (if quantity != 1: "doors" else: "door")
> data = (if hasattr(s, 'open'): s.readlines() else: s.split())
s.split('\n') perhaps?
> z = 1.0 + (if abs(z) < .0001: 0 else: z)
> t = v[index] = (if t<=0: t-1.0 else: -sigma /(t + 1.0))
> return (if len(s)<10: insertsort(s) else: quicksort(s))
> Note, the examples are required but will not be used.
> Try to get them right, but it is okay if they are wrong.
--
yes-I'm-nit-picking-ly yours
Tim Evans
>Gerrit Holl <ger...@nl.linux.org> wrote previously:
>|Although it's true that if one rejects all, it's strange to have
>|to do this.
>
>Perhaps Raymond will specify otherwise, but it seems to me that if you
>wish to vote to reject the introduction of any ternary operator, you
>could fill out the following:
>
> Q reject NONE
> Q reject NONE
> Q reject NONE
> Voter Name
> NONE
> NONE
> NONE
> NONE
> NONE
I think you should probably make the effort to fill in the examples
using existing methods to show you understand the consequences of your
vote - you may have difficulty with the single line constraint if you
want your examples to be readable, but no doubt a blank line separator
for multiline examples would be accepted if necessary.
>That seems to meet all the rules. Of course, I guess this leaves the
>danger that a new ternary expression spelled "NONE" (for every C, x, y)
>will be added to Python :-).
Of course, it would be nice if a single keyword could magically work
out what is wanted - lets enhance that proposal to the point where the
single keyword 'abracadabra' will magically work out what the user
wants done and do it for him!
Oh hang on - I'd end up redundant, so let's not.
--
steve at ninereeds dot fsnet dot co dot uk
I believe the ballot should have a couple of places to vote before
we have to select or reject specific "styles". Like:
0. Proposed: the addition of a short-circuiting ternary operator to Python
[ ] In favor
[ ] In favor with reservations
[ ] Neutral
[ ] Opposed with reservations
[ ] Opposed
0.b. Should the ternary operator be nestable?
[ ] Yes
[ ] Neutral
[ ] No
0.c. Must the conditional precede both consequents?
[ ] Yes
[ ] Neutral
[ ] No
For myself, I'm neutral as to whether a ternary operator is
introduced, but I'm opposed unless the condition precedes the two
consequents. In other words, I oppose the form 'x if C else y' and
all variants.
I am okay with 'C then x else y' and variants.
I oppose all 'C ? x : y' variants, in that I don't believe complex
punctuation syntax is "pythonic".
It's confusing that I can list three syntax options, and either accept
or reject each. So, should I be a positivist, and vote in favor of all
the 'C then x else y' variants? Should I be negativist, and vote
against the forms I dislike?
Finally, I'm not sure that one week is enough time for everyone who
might have a valid opinion to chime in. For example, I was taking a
course last week, and fully participating in the decision process
would have been quite a bit more difficult if this call for votes had
come a week earlier.
Nick
--
# sigmask.py || version 0.2 || 2003-01-07 || Feed this to your Python.
print reduce(lambda x,y:x+chr(ord(y)-1),'Ojdl!Wbshjti!=obwAqbusjpu/ofu?','')
Yes, very good idea. I actually decided to reject all preferences after
trying them out. Reason: I might actually have to read someone's code with
that nonsense in it some day. :(((
--
Sheila King
http://www.thinkspot.net/sheila/
http://www.k12groups.org/
i don't like it enough to ask for anything that'd just end up unreadably
messy, or that would stand out like a sore thumb looking nothing like the
rest of the language. i'm already leery of using list comprehensions
simply because the aesthetics of that syntax, in my subjective view, don't
"look like python" enough for my tastes; they remind me of inline assembly
or SQL in C or somesuch.
oh, and your proposed ballot is too confusing and complicated for me to
figure out. i could perhaps write a voting front-end for it, but that
doesn't seem worth the effort, so i'll just post a rambling commentary to
the 'net instead; i'm more familiar with that...
On Sun, 02 Mar 2003 02:25:46 +0000, Raymond Hettinger wrote:
> CHOICES (taken from Erik Max Francis's posting of seconded choices)
> -------
> A. x if C else y
sortof reminds me of Perl's reverted "if/unless" syntax. i could deal with
it, but too much turning the "usual" order of the conditional and
consequent inside out takes mental effort to read.
> B. if C then x else y
this one i would heartily support. probably my favourite out of these. if
parenthesizing the conditional and possible consequents turns out to be
necessary, i wouldn't mind that either.
> C. (if C: x else: y)
much the same as (B), only terser. maybe just a bit too terse, the
previous form seems more explicit about what it is and what it does.
> D. C ? x : y
> E. C ? x ! y
variations on the "standard" C-or-Perl-style ternary. i don't mind this
style at all - _in a language where ALL the code looks like that_. in
python, this would stand out, at least to my aesthetic sensibilities. i
wouldn't like it.
> F. cond(C, x, y)
shades of reduce(), map() or similar functional-ish constructs. i don't
mind having those in the language, but i don't use them much, either. i'd
probably use this, but maybe not as frequently as i might other syntaxes.
> G. C ?? x || y
all the disadvantages of options (D) and (E), without their advantage in
terseness. no thanks.
> H. C then x else y
eer.. i had to read that one twice to see what it said. something tells me
i'd keep on having to do that, so no thanks.
> I. x when C else y
more of the inside-out logic of (H) and (A). _i_ find it mildly confusing,
but this form still isn't too bad. maybe i could live with it, but IMAO
this isn't the best option.
> J. C ? x else y
> K. C -> x else y
> L. C -> (x, y)
see (G) above.
> M. [x if C else y]
> N. ifelse C: x else y
> O. <if C then x else y>
and these just get ever weirder and weirder... how would you tell (M)
apart from a regular list comprehension? and introducing a new meaning for
angle brackets like (O) would, well, it just somehow upsets me. sorry, no
thanks.
> P. C and x else y
ah, one i could get to like! this would be my runner-up candidate if
option (B) didn't make it; i'd have a hard time deciding between this and
(F), but likely i'd go for this. again, if parenthesizing the conditional
and/or consequents is necessary, i'd be fine with that.
> Q. any write-in vote
i can't think of anything that would be markedly better or worse than
what's been presented, so i'll shut up now.
--
PGP/GnuPG key (ID 1024D/3AC87BD1) available from keyservers everywhere
Key fingerprint = FA8D 5EA4 E7DC 84B3 64BC 410C 7AEE 54CD 3AC8 7BD1
"...if you can fill the unforgiving minute
with sixty seconds' worth of distance run..."
> oh, and your proposed ballot is too confusing and complicated for me to
> figure out.
And yet, no butterfly jokes so far...
Me too, I started to type in my prefered syntax, and I hated it.
But, I can't figure out how to vote "no ternary please"
In 3+years of Python/Zope, I've only had a few places where I could use it
anyway
What if s.readlines() returns [] ?
>>> import StringIO
>>> class MyStringIO(StringIO.StringIO):
... def open(self):
... pass
...
>>> s = MyStringIO("")
>>> data = (hasattr(s, 'open') and s.readlines() or s.split())
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
AttributeError: MyStringIO instance has no attribute 'split'
>>>
The second case with the "and 0" *always* returns 1.0 + z, as in
>>> z = 0.0001
>>> z = 1.0 + (abs(z) < .0001 and 0 or z)
>>> z
1.0001
>>>
If linsort returns None or some other false value then the
third case also my call qsort, eg, when len(s) == 0.
The and/or mechanism is not a general catch-all for a ternary
if/else operator. It should be used judiciously, if at all.
Andrew
da...@dalkescientific.com
> Sheila King <use...@thinkspot.net> wrote:
>
> > Yes, very good idea. I actually decided to reject all preferences after
> > trying them out. Reason: I might actually have to read someone's code with
> > that nonsense in it some day. :(((
>
> Nonsense is nonsense is nonsense. Was this your vote? :)
No, the below is not my vote. I'd certainly rather you hadn't put my name
in such a bogus example, as who knows what people will make of it at a
later time on Usenet. I've removed my name from the quoted example below.
> Q accept c and x or y
> Q accept (c and [x] or [y])[0]
> Q accept (lambda: x, lambda: y)[not c]()
> Someone Fictitious
> x = "door" + (quantity>1 and "s" or "")
> data = (hasattr(s, 'open') and s.readlines() or s.split())
> z = 1.0 + (abs(z) < .0001 and 0 or z)
> t = v[index] = (t<=0 and t-1.0 or -sigma /(t + 1.0))
> No, the below is not my vote. I'd certainly rather you hadn't put my name
> in such a bogus example, as who knows what people will make of it at a
> later time on Usenet. I've removed my name from the quoted example below.
Sincerest apologies. The inclusion of your name is so obviously wrong
in hindsight. No offence was intended.
--
Tabby
exit = { 0: 'no exit',
1: 'a door' }.get(quantity,
'%s doors' % quantity)
Or, the more 'obvious' ...
if 0 == quantity: exit = 'no exit'
elif 1 == quantity: exit = 'a door'
else: exit = '%s doors' % quantity
The first construct has two advantages over the more 'obvious'
solution:
1. It's clear that I'm making an assignment to exit
2. I don't have to duplicate the ugly '== quantity'
each time.
However, the first construct brings with it two problems:
1. The 'else' case is kinda ugly.
2. It doesn't short-circut cleanly, to have the short-circut
behavior you need to use lambda's as the mapping values
and then invoke the result...
So, if you asked me, what I'd like is a hybrid of the two options
above, a nicer-looking short-circuting in-line mapping:
exit = select quantity
case 0: 'no exit'
case 1: 'a door'
else: '%s doors' % quantity
#NOTE: new lines/indentation is mandatory in this proposal
IMHO, the other options in the survey are quite clean
when you look at it this way:
data = select hasattr(s,'open')
case true: s.readlines()
else: s.split()
z = 1.0 + select abs(z) < .0001
case true: 0
else: z
t = v[index] = select t <= 0
case true: (t-1.0)
else: -sigma / (t + 1.0)
return select len(s) < 10
case true: linsort(s)
else: qsort(s)
...
The other advantage of this mechanism is that the
semantics could be made a bit more flexible by requiring
the case item to be a predicate -- a boolean function
with one argument, the item being selected upon. Thus,
z = 1.0 + select abs(z)
case lt(.0001): 0
case gt(.5): .5
else: -sigma / (t + 1.0)
score = select die
case 1: -2
case 2: -1
case between(3,4): 0
case 5: +1
case 6: +2
else:
raise "invalid die roll %d " % roll
Since the items 1,2,5,6 arn't predicates, then the
"equal" predicate is assumed.
Now... _this_ I would really find useful.
Best,
Clark
Good work.
John Roth
"Clark C. Evans" <c...@clarkevans.com> wrote in message
news:mailman.1046774818...@python.org...
if quantity > 0: exit = "door"
else: exit = "doors"
I'd rather have something like...
exit = (if quantity > 0: 'door'
else: 'doors')
However, the idea of moving the 'else' part onto the 1st line
is where it gets ugly and where I cry uncle. Here are the
examples with mandatory parens and new line...
x = "door" + (if quantity > 1: 's'
else: '')
data = (if hasatttr(s, 'open'):
s.readlines()
else:
s.split()
)
z = 1.0 + (if abs(z) < .0001: 0
else: z)
t = v[index] = (if t <= 0:
t-1.0
else:
-sigma / (t+1.0)
)
return (if len(s) < 10: linesort(s)
else: qsort(s))
I think that these are probably more clear than the
traditional if/else statement.
Clark
P.S. That said, I like the previous select/case proposal better.
Consider the following two constructs, ignoring the syntax
details for a moment:
if <condition>:
<variable> = <value-a> # first assignment
else:
<variable> = <value-b> # second assignment
In this example, the first and second assignment have
a parallel structure; but the '<variable> =' part happens
to be duplicated. This is somewhat inefficient for
two reasons:
(a) someone reading the code has to scan the whole
structure and determine that there is a parallel
structure, where the variable is assigned a value
in either case of the condition; and
(b) someone writing/editing the code has to make sure
that the variable is the same in both places or
else the parallel structure is broken.
Compare this example to the following...
<variable> = ( if <condition>:
<value-a>
else:
<value-b>
)
In this case, the data-duplication is eliminated; for this
particular syntax we trade additional indentation and
parenthesis for the pleasure of only having to write the
variable once. The result:
(a) someone reading the structure can immediately
see that the goal of the fragment is to assign
a value to the variable, in all cases.
(b) someone writing/editing the structure need only
type the variable name once; the compiler worries
about maintaining the parallel structure.
In summary, people want a way to make a conditional structure
'subordinate' to an assignment. So. If we can all agree that
this is a weakness of Python, then we can look of various ways
to solve the problem. Perhaps a "terinary operator" isn't
the best way to do it.
...
Besides the left hand side of the assignment, there happens
to be another parallel structure which occurs often...
if a == X:
b = Q
elif a == Y:
b = R
else:
b = S
In this case, not only is 'b = ' duplicated three times,
but 'a ==' is duplicated twice. These two can be combined
into the select/case pattern:
b = select a:
case X: Q
case Y: R
else: S
So, really, we have two categories of duplication:
(a) the left hand side of the assignment
(b) the left hand side of the conditional
Perhaps we can scratch two itches at the same time? The syntax
really doesn't matter now; what matters is that we agree on the
problem. Then we can throw up our best syntaxes and let Guido
choose and work his magic...
clark
> I was thinking, perhaps if people first agreed on the problem
> finding a solution could become more of a detail. Here is a
> stab at the 'terinary operator' problem.
>
> Consider the following two constructs, ignoring the syntax
> details for a moment:
>
> if <condition>:
> <variable> = <value-a> # first assignment
> else:
> <variable> = <value-b> # second assignment
>
> In this example, the first and second assignment have
> a parallel structure; but the '<variable> =' part happens
> to be duplicated. This is somewhat inefficient for
> two reasons:
>
> (a) someone reading the code has to scan the whole
> structure and determine that there is a parallel
> structure, where the variable is assigned a value
> in either case of the condition; and
>
> (b) someone writing/editing the code has to make sure
> that the variable is the same in both places or
> else the parallel structure is broken.
Good points -- basically similar to arguments for having
such augmented-assignment operators as += in the language
(avoiding <variable> = <variable> <operator> <value>
redundancy both in reading and writing the code).
> Besides the left hand side of the assignment, there happens
> to be another parallel structure which occurs often...
>
> if a == X:
> b = Q
> elif a == Y:
> b = R
> else:
> b = S
>
> In this case, not only is 'b = ' duplicated three times,
> but 'a ==' is duplicated twice. These two can be combined
Hmmm, well, yes, but this is somewhat less convincing to me.
> into the select/case pattern:
>
> b = select a:
> case X: Q
> case Y: R
> else: S
>
> So, really, we have two categories of duplication:
>
> (a) the left hand side of the assignment
> (b) the left hand side of the conditional
Yes, but they're orthogonal -- i.e. the second case might
just as well be:
if a == X:
c = Q
elif a == Y:
d = R
else:
e = S
which only shows redundancy kind [b], not kind [a]. Why
are we assuming the two redundancies go together?
> Perhaps we can scratch two itches at the same time? The syntax
> really doesn't matter now; what matters is that we agree on the
> problem. Then we can throw up our best syntaxes and let Guido
> choose and work his magic...
I like this analysis, but I do not understand the reason to
assume the two redundancy problems should occur together.
Alex
I think you missed
(c) it takes up too much precious screen estate
otherwise I agree, and I think a general switch expression might
be more interesting, but as you propose the beast it only deals
with straight comparision. What about enhancing it like:
b = (if a <op>:
on X: Q
on Y: R
else: S)
being equivalent to:
if a <op) X:
b = Q
elif a <op> Y:
b = R
else:
b = S
And a possible shortening syntactic sugaring could produce:
b = (if a <opt>; on X: Q; on Y: R; else: S)
The semicolon being used to allow to put on one line what otherwise
needs two, like with multiple statements on a single line. The parens
being required to allow nesting and making scope explicit. And leaving
finding proper names for if (select) and on (case) for later to decide.
I think something along these lines has been proposed during the
recent ternary operator tempest, but I lost track.
Anyway, by now it looks so troublesome that I rather not have it in:)
--
groetjes, carel
This is a very confusing votation system :-(
I think people can easily get confused (as I was) and actually favor
what they
dislike the most. Just to point out again the shortcomings of
this strange idea of rejecting the most loved alternative ....
--
Michele Simionato - Dept. of Physics and Astronomy
210 Allen Hall Pittsburgh PA 15260 U.S.A.
Phone: 001-412-624-9041 Fax: 001-412-624-9163
Home-page: http://www.phyast.pitt.edu/~micheles/
Yes, there is a lot of duplicated "text" in the first
case, and the second case corrects that. But you don't
need new syntax to be able to make it better, you already
have dictionaries:
b = { Q:X, R:Y }.get(a,S)
At least to me, it's a lot more readable, doesn't involve
new syntax, and can grow to a larget amount of options
if needed.
And it isn't limited to constant expressions inside the
dictionary, as this IDLE session demonstrates:
>>> a, A = "a", "Peter"
>>> b, B = "b", "John"
>>> c, C = "c", "Ernest"
>>> default = "Spanish Inquisition"
>>> def chooser(choice):
global a, A, b, B, c, C, default
return { a:A, b:B, c:C }.get(choice, default)
>>> print chooser("a")
Peter
>>> print chooser("c")
Ernest
>>> print chooser("x")
Spanish Inquisition
>>> print chooser("b")
John
>>> print chooser("John")
Spanish Inquisition
>>> B = "Ironman"
>>> print chooser("b")
Ironman
>>> A = "Raquel Welch"
>>> C = "Ozzy Osbourne"
>>> default = "Eric Idle"
>>> print chooser("a")
Raquel Welch
>>> print chooser("d")
Eric Idle
>>> print chooser("c")
Ozzy Osbourne
>>> c = "zz"
>>> print chooser("zz")
Ozzy Osbourne
>>>
The "need" for a ternary operator in many occasions is
created by not knowing the "correct" pythonic construction
which expresses that which you need to do. Python's
interactive nature helps you explore all that.
Ternary operators are good to select between two (and
let's keep it at two) expressions which might have
(severe?) side-effects, there lies the need for short-
circuiting.
In the above example, imagine evaluating A, B or C could
have side-effects; in that case, upon constructing the
selection dictionary, all side-effects would have been
triggered, so this construction would be no good. It
could be adapted, by changing the function chooser()
like so:
>>> def chooser(option):
try:
return { a:lambda:A,
b:lambda:B,
c:lambda:C }[option]()
except KeyError:
return default
It becomes a bit more complex, but still quite simple.
-gustavo
Not on a par with Italian electoral laws (which you may have
already blissfully forgotten from your Pennsylvania home, as
far as I know...), but, yes, pretty bad, I agree.
Alex
THE JUDEAN PEOPLE'S FRONT?!
Seriously, it is much better to conduct a debate or vote in terms of
what you like than in terms of what you dislike.
The things you hate the most tend to be the things where you are the
most in conflict with yourself; things that you might have almost
liked, but for some reason chose not to. Decidedly bad things do
not evoke such strong emotion.
- Anders
I think Martijn raised some serious points.
The vote announcment should indeed contain *no* literal PEP.*308
especially not in the subject line. Like others, i only noticed
it by coincident (having hit CTRL-D already).
And the vote absolutely needs a clean, obvious simple
"no ternary needed" choice.
the vote-announcement should be re-posted with these two bugs
fixed. easy enough.
holger
I have not run in to a case where it is needed yet. I don't think that there
is any reason to make reading code more complicated. If the user really want
to do this, then they can always define their own function that takes three
paramters.
def foo(booleanTest, condition1, condition2):
if booleanTest:
return condition1
return condition2
def foo2:
...
a = foo(someTest, condition1, condition2)
...
I don't like a line serving two purposes, which a ternary would introduce.
> I will vote no ternary operator.
>
> I have not run in to a case where it is needed yet. I don't think that there
> is any reason to make reading code more complicated. If the user really want
> to do this, then they can always define their own function that takes three
> paramters.
No, as that does not support short-circuiting. The conditional operator is
_not_ equivalent to a three-arg function. I know, I know, this has been
discussed to death, but many of the 'no' votes have appeared to be from
the 'you can simply do that with a function' camp, which is unfortunate
because those are sort of false 'no' votes since it's based (at least in
part) on a misunderstanding.
Also, the 'you can do this another way' vote is unfortunate because IMO it
misses the point. The language is Turing complete, so pretty much all
features at this point can be done another way. We didn't strictly _need_
list comprehensions, lambdas, augmented assignments, generators, classes,
etc., etc., but having them is very powerful, expressive, useful,
whatever. Obviously many people feel that the conditional operator is not
powerful, expressive, useful, whatever _enough_ to warrant adding it to
the language - and that's fine, but please don't simply vote against it
because it's not essential.
Just my two cents,
-Dave
> This voting procedure forces me to write what I like the best (even
> in the 'reject' case, I must check the last hated expression). I
> have no way to express what I dislike the most.
I have now voted, and no longer really care, but yes, I agree that
this was the most annoying aspect of the voting system. Not being able
to say how much I *loathe*
(if c: x else: y)
was a definite lack for me. And it's a shame, because I think it's
useful information (a syntax which people either love or hate, with no
middle ground, may be less preferable than one which evokes no such
strong opinions).
But what the heck.
Paul.
--
This signature intentionally left blank
Thank you for commenting. Below is follow up to your response
and an improved "operator" mechanism for the case/switch statement
due to musings on Carel's option.
On Tue, Mar 04, 2003 at 04:05:12PM +0100, Alex Martelli wrote:
| Good points -- basically similar to arguments for having
| such augmented-assignment operators as += in the language
| (avoiding <variable> = <variable> <operator> <value>
| redundancy both in reading and writing the code).
Yes.
| > So, really, we have two categories of duplication:
| >
| > (a) the left hand side of the assignment
| > (b) the left hand side of the conditional
|
| Yes, but they're orthogonal -- i.e. the second case might
| just as well be:
|
| if a == X:
| c = Q
| elif a == Y:
| d = R
| else:
| e = S
|
| which only shows redundancy kind [b], not kind [a]. Why
| are we assuming the two redundancies go together?
Correct. However, empirically from my production code
(in production at 20+ companies), both types of redundancy
tend to cluster together. Thus, it makes sense to me to
try and think of a mechanism which allows us to treat them
together. Think of it as an 80/20 optimization. For example,
I often have code like...
if 0 == quantity: exit = 'no exit'
elif 1 == quantity: exit = 'a door'
else: exit = '%s doors' % quantity
which I often re-write with the "mapping-idiom" as:
exit = { 0: 'no exit',
1: 'a door' }.get(quantity,
'%s doors' % quantity)
This gains the advantage of normalizing both type [a]
and type [b] redundancies, however, it comes at a cost:
1. the code isn't "obvious" to newbies making it
harder to maintain -- making my code obscure
2. the code doesn't short-circuti; Yes, you can have
function pointers returned from the mapping and
then invoke the function... but this isn't any
more obvious or easy to read!
Thus, a new syntax-level construct which combines this
pattern in a easy to understand manner /w short-circuts
would be useful...
exit = select quantity
case 0: 'no exit'
case 1: 'a door'
else: "%s doors" % quantity
The examples given in the survey are very cleanly
expressed with this syntax.
data = select hasattr(s,'open')
case true: s.readlines()
else: s.split()
z = 1.0 + select abs(z) < .0001
case true: 0
else: z
t = v[index] = select t <= 0
case true: (t-1.0)
else: -sigma / (t + 1.0)
return select len(s) < 10
case true: linsort(s)
else: qsort(s)
| > Perhaps we can scratch two itches at the same time? The syntax
| > really doesn't matter now; what matters is that we agree on the
| > problem. Then we can throw up our best syntaxes and let Guido
| > choose and work his magic...
|
| I like this analysis, but I do not understand the reason to
| assume the two redundancy problems should occur together.
I've found a slight hybrid of the combination common, where
[a] and [b] occur, but the 'operator' differs. In this
situation, we could allow an optional boolean function/operator
right after the case statement. The first argument to the operator
would be the item selected, and the remaining arguments are used
up to the colon. If the operator is missing, it is assumed to
be the '==' operator.
z = 1.0 + select abs(z)
case < .0001: 0
case > .5: .5
else: -sigma / (t + 1.0)
score = select die
case 1: -2
case 2: -1
case between 3,4: 0
case 5: +1
case 6: +2
else: raise "invalid die roll %d " % roll
For a die roll of 8, for example, the 'between'
function would be called with the tuple (8,3,4)
and would clearly return false.
On Tue, Mar 04, 2003 at 09:09:52AM -0600, sism...@hebmex.com wrote:
| Yes, there is a lot of duplicated "text" in the first
| case, and the second case corrects that. But you don't
| need new syntax to be able to make it better, you already
| have dictionaries:
|
| b = { Q:X, R:Y }.get(a,S)
|
| At least to me, it's a lot more readable, doesn't involve
| new syntax, and can grow to a larget amount of options
| if needed.
While it may be common, this idiom isn't very intuitive
for newbies. It took several examples before I caught
on... and even then I'm not really happy with the result.
| In the above example, imagine evaluating A, B or C could
| have side-effects; in that case, upon constructing the
| selection dictionary, all side-effects would have been
| triggered, so this construction would be no good. It
| could be adapted, by changing the function chooser()
| like so:
|
| >>> def chooser(option):
| try:
| return { a:lambda:A,
| b:lambda:B,
| c:lambda:C }[option]()
| except KeyError:
| return default
Yes, but once again, this isn't obvious to newbies
nor is it very readable. In short, ick.
On Tue, Mar 04, 2003 at 04:27:47PM +0100, Carel Fellinger wrote:
|
| I think you missed
|
| (c) it takes up too much precious screen estate
|
Exactly. I purposefully left his one out. I think that much of
the Python community would disagree with you here. Python isn't
and shouldn't be horizontally efficient (like C or Java).
| otherwise I agree, and I think a general switch expression might
| be more interesting, but as you propose the beast it only deals
| with straight comparision. What about enhancing it like:
|
| b = (if a <op>:
| on X: Q
| on Y: R
| else: S)
I merged your idea of the operator with my idea of the predicates,
see above. Thanks. This seems to be an improvement. I'm not yet
certain that it is worth the complexity, but it is nice.
| And a possible shortening syntactic sugaring could produce:
|
| b = (if a <opt>; on X: Q; on Y: R; else: S)
Here is where you add your (c) requirement, and I think it is
also the point where a good part of the Python community
(who came to Python for clearly indented logical structures)
disagrees.
| Anyway, by now it looks so troublesome that I rather not have it in:)
No doubt. But I think where you went wrong is that (c) isn't
a requirement. Python need not be horizontally efficient.
Best,
Clark
Well, I'm just relying on the BDFL to simply not put any of these
abominations into the l;anguage We Love. I'm -1 on them all,
regards
--
Steve Holden http://www.holdenweb.com/
Python Web Programming http://pydish.holdenweb.com/pwp/
Register for PyCon now! http://www.python.org/pycon/reg.html
Agreed. But I think you are throwing out the baby with the
bathwater here. What is useful about the terinary operator
is that for assignments it is clear that the lhs is uniform.
z_of_useful_length = select abs(z_of_useful_length)
case < .0001: 1.0
else: 1.0 + z_of_useful_length
In this case it is clear that you are making an assignment
with two choices. This syntax also extends nicely to
facilitate more than one case.
Clark
The weakness is that Python has a "dangling else" ambiguity which requires
indentation to disambiguate (i.e. the if-else must occupy two lines
minimum).
One would like to write something like
A = if <cond> then B else C endif (not Python!)
Ignoring the assignment for awhile, can get close to a one-liner if with
if <cond>: B; else: C (not valid Python)
Arguably (and incorrectly argued), the ";" allows this to be written as a
one-liner To see why this can never be valid Python, consider nesting "if
<cond2>: D" for B to yield:
if <cond>: if <cond2>: D; else: C
It is truly ambiguous whether this parses as:
if <cond>:
if <cond2>: D;
else: C
or
if <cond>:
if <cond2>: D;
else: C
The solution I see for resolving "dangling else" is to put a token at the
end, just as I have in the "endif" in the first example (this example is
from PLD2, a language I designed). I think tacking something onto if-end is
impractical without something new tacked on at the beginning to notify the
interpreter to parse for the something on the end.
From where I sit, resolving "dangling else" in Python without indentation
just introduces cruft into the language. There are things my language will
not do well. A single-line "if" does not look like a good fit in Python.
I would be inclined here to not change anything.
> <variable> = ( if <condition>:
> <value-a>
> else:
> <value-b>
> )
I presume that
<variable> = ( if <condition>: value-s>)
is also allowed. Does this extend to
<variable> = subroutine_call(( if <condition>: value-s>))
Where the outer parens show that subroutine_call is being invoked and inner
parens show if expression is being evaluated.
--
Dennis Reinhardt
The assignment is spread across lines 1,2,3 and the comparison is on lines
1,2. I don't see the baby which is thrown out here.
DR:
> | if abs(z_of_useful_length) < .0001:
> | z_of_useful_length = 1.0
> | else:
> | z_of_useful_length += 1.0
> |
> | ... much more readable.
I think my example based on existing syntax is still more readable.
Existing syntax allowing for single lhs is:
def ternary(in_z):
if abs(in_z)< .0001: return 1.0
else: return 1.0 + in_z
z_of_useful_length = ternary(z_of_useful_length)
--
Dennis Reinhardt
Den...@dair.com
http://www.dair.com
Q accept switch-case
Z deny everything else!
Dedication:
To those who hate the terinary operator beacuse it isn't pythonic...
Background:
After looking over much of my Python source code, I found that
where I thought I needed a terinary operator, I ended
up taking one of two paths:
if 0 == quantity: exit = 'no exit'
elif 1 == quantity: exit = 'a door'
else: exit = '%s doors' % quantity
Or, the more concise mapping-idiom:
exit = { 0: 'no exit',
1: 'a door' }.get(quantity,
'%s doors' % quantity)
The latter construct has two advantages over the if/else
statement level solution:
1. It's clear that I'm making an assignment to exit;
in effect the "exit =" isn't duplicated and this
aids in authoring/maintenance/reading.
2. The ugly '== quantity' isn't duplicated for each line,
once again improving maintenance.
However, the mapping-idiom has three problems:
1. The conditional switch isn't exactly "obvious" here
unless you're a Python vetran, this hurts in the
maintenance arena; besides the 'else' case is ugly.
2. It doesn't short-circut cleanly, to do a short-circut
you need to use lambda's... ick; further, it results in
the construction of a mapping which may not really help
out optimizations.
3. It really doesn't facilitate the use whitespace/indentation
to re-inforce a visual representation of the program's
structure.
Philosophy:
The whole rationale for this construct is to reduce data
duplication (both the assignments and conditional tests)
to increase maintenance.
The goal is not to save on vertical screen realistate by
enabling multi-line constructs to be "jumbled" into a
single line. It seems that many people are asking for the
terinary option for the latter.
Instead, this proposal seeks to engage Python's unique approach
to syntax by using whitespace to enhance the visual representation
of the program's structure. Many Python converts are here exactly
beacuse Python is very readable and thus maintainable. This proposal
is here soley to re-enforce this "pythonic" approach to coding.
Proposal:
The proposal introduces a 'select' or 'switch' keyword which creates
an indented expression block. Instead of the following,
exit = { 0: 'no exit',
1: 'a door' }.get(quantity,
'%s doors' % quantity)
You could write,
exit = select quantity
case 0: 'no exit'
case 1: 'a door'
else: '%s doors' % quantity
This proposal gives you the power of the mapping-idiom without
the uglyness. It expresses the intent of the construct in a
very human readable manner using whitespace smartly.
While the above is "good", it assumes an equality operator. So
that the structure is more generic, his proposal allows an optional
operator (a function taking 2 or more value and returning a boolean)
immediately following the 'case' label,
z = 1.0 + select abs(z)
case < .0001: 0
case > .5: .5
else: -sigma / (t + 1.0)
Note that the examples given in the proposal are thus
very easily expressed using this notion:
data = select hasattr(s,'open')
case true: s.readlines()
else: s.split()
z = 1.0 + select abs(z)
case < .0001: 0
else: z
t = v[index] = select t
case <= 0: t - 1.0
else: -sigma / (t + 1.0)
return select len(s)
case < 10: linsort(s)
else: qsort(s)
The 'operator' need not be binary, one could, for example,
provide a terinary operator, such as:
def between(cmp,rhs,lhs): return cmp >= rhs and cmp <= lhs
score = select die
case 1: -2
case 2: -1
case between 3,4: 0
case 5: +1
case 6: +2
else: raise "invalid die roll %d " % roll
Summary:
The proposal thus creates a flexible mechanism for avoiding
the excessive duplication of assignment and equality fragments
within a conditional assignment nest; it does so through a
new expression structure which, like the rest of Python, uses
indentation for structure.
This proposal thus provides the pratical benefit of a terinary
operator, while at the same time opening the door to a rich
(and quite readable) conditional assignment mechanism.
In particular, this proposal rejects the rationale for 'terinary'
operator as a way to trade horizontal screen realestate for
vertical space; as this rationale is in direct opposition to
the fundamental principle of readability. And as such, the
proposal explicitly does not include a way to include multiple
case labels on the same line.
Credits:
Alex Martelli for validating the elimination of needless-duplication
of code as the primary goal for the construct; and
Carel Fellinger for presenting the idea of a plugable predicate/operator
Raymond Hettinger for asking me to write this up more or less formally
/S
>--
>http://mail.python.org/mailman/listinfo/python-list
>
--
Steven Cummings
Columbia, MO
Email: cummi...@netscape.net
AIM: cummingscs
ICQ: 3330114
__________________________________________________________________
The NEW Netscape 7.0 browser is now available. Upgrade now! http://channels.netscape.com/ns/browsers/download.jsp
Get your own FREE, personal Netscape Mail account today at http://webmail.netscape.com/
Why is this a weakness? I like indentation. I use Python exactly
beacuse it uses indentation to show me structure. The biggest problem
I have with all of the 'terinary' options is that they are
single-line solutions.
The only solution that the terinary operator needs to solve
is a way to provide for conditional logic within an expression
intead of forcing the programmer to use statements.
After the select/case option presented previously, my second
best option would be something like...
var = (if 1 == x: 'yes'
else: 'no')
Where the 'else' must be in the same column as the
corresponding if.
Getting it to fit on a single line is just an unnecessary
distraction, and, IMHO, one that is bogging down the whole
discussion down... and preventing a good mechanism to
express conditional logic within an expression.
Grins,
Clark
switch-case:
data = select hasattr(s,'open')
case true: s.readlines()
else: s.split()
z = 1.0 + select abs(z)
case < .0001: 0
else: z
t = v[index] = select t
case <= 0: t - 1.0
else: -sigma / (t + 1.0)
return select len(s)
case < 10: linsort(s)
else: qsort(s)
multi-line if/else:
data = (if hasattr(s,'open'): s.readlines()
else: s.split())
z = 1.0 + (if abs(z) < .0001: 0
else: z)
t = v[index] = (if t <= 0: t - 1.0
else: -sigma / (t + 1.0))
return (if len(s) < 10: linsort(s)
else: qsort(s))
> After some encouragement by Raymond, I'd like to add one more
> item to the survey, if you like what follows perhaps you can
> even *change* your vote (Raymond?) to include:
>
> Q accept switch-case
> Z deny everything else!
I think it's a tad late for this. (First of all, a switch...case
expression isn't even at issue for PEP 308; that should be reserved for
antoher PEP.)
The voting process has been confused enough as it is. Amending it at
this late date to add another option doesn't seem like a very good idea
at all. (For one thing, how many people who have already voted are
going to bother scrutinizing updates to the voting process?)
--
Erik Max Francis / m...@alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE
/ \ And your daddy died for you / And I'll do the same
\__/ India Arie
Bosskey.net: Counter-Strike / http://www.bosskey.net/cs/
A personal guide to Counter-Strike.
> After the select/case option presented previously, my second
> best option would be something like...
>
> var = (if 1 == x: 'yes'
> else: 'no')
>
> Where the 'else' must be in the same column as the
> corresponding if.
This is already completely compatible with the primary form proposed in
the PEP. You can insert whitespace and indentation to your heart's
content.
Quite right. A switch/case statement isn't at issue for PEP 308,
and I was incorrect to label this proposal as such -- switch/case
is a block level construct which contains statements. I'm not
proposing that.
This proposal is for a select/when *expression* which is simply
a generalization of a terinary operator, and equivalent to
some of the "elif" like options on the table. So, this
proposal fits right in with the spirit of the PEP.
| The voting process has been confused enough as it is. Amending it at
| this late date to add another option doesn't seem like a very good idea
| at all. (For one thing, how many people who have already voted are
| going to bother scrutinizing updates to the voting process?)
Well, I'd like to see what people think; I guess Guido can
take the "late comer" status into consideration. ;)
Sorry for picking the wrong words,
Clark
CASE WHEN value = 0 THEN 'zero'
WHEN value = 2 THEN 'one'
ELSE 'unknown'
END
and...
CASE value
WHEN 0 THEN 'zero'
WHEN 2 THEN 'one'
ELSE 'UNKNOWN'
END
So, I was thinking about three modifications to the proposal,
1. Change 'case' to 'when' so that confusion with
switch/case is harder to make.
2. Allow the 'select' keyword to be missing so that
the 'when' items can be plain old boolean expressions
like the 1st case above.
3. Make it clear in the motivation that this is an
expression (with a value) not a block structure;
as a result, this greatly improves the power of
lambda functions which as I understand can't
contain statements, and thus can't do if/then
sorts of logic.
The updated proposal/announcement...
-----
After some encouragement by Raymond, I'd like to add one more
item to the survey, if you like what follows perhaps you can
even *change* your vote (Raymond?) to include:
Q accept select/when
Z deny everything else!
Dedication:
Background:
Philosophy:
The whole rationale for this construct is to introduce
a conditional 'expression' construct, and further to provide
this construct in such a way as to reduce duplication (of both
assignment and conditional fragments) to increase maintenance.
The goal is not to save on vertical screen realistate by
enabling multi-line constructs to be "jumbled" into a
single line. It seems that many people are asking for the
terinary option for the latter.
Instead, this proposal seeks to engage Python's unique approach
to syntax by using whitespace to enhance the visual representation
of the program's structure. Many Python converts are here exactly
beacuse Python is very readable and thus maintainable. This proposal
is here soley to re-enforce this "pythonic" approach to coding.
Proposal:
The proposal introduces a 'select' or 'switch' keyword which creates
an indented expression block. Instead of the following,
exit = { 0: 'no exit',
1: 'a door' }.get(quantity,
'%s doors' % quantity)
You could write,
exit = select quantity
when 0: 'no exit'
when 1: 'a door'
else: '%s doors' % quantity
This proposal gives you the power of the mapping-idiom without
the uglyness. It expresses the intent of the construct in a
very human readable manner using whitespace smartly.
While the above is "good", it assumes an equality operator. So
that the structure is more generic, his proposal allows an optional
operator (a function taking 2 or more value and returning a boolean)
immediately following the 'case' label,
z = 1.0 + select abs(z)
when < .0001: 0
when > .5: .5
else: -sigma / (t + 1.0)
Note that the examples given in the proposal are thus
very easily expressed using this notion:
data = select hasattr(s,'open')
when true: s.readlines()
else: s.split()
z = 1.0 + select abs(z)
when < .0001: 0
else: z
t = v[index] = select t
when <= 0: t - 1.0
else: -sigma / (t + 1.0)
return select len(s)
when < 10: linsort(s)
else: qsort(s)
The 'operator' need not be binary, one could, for example,
provide a terinary operator, such as:
def between(cmp,rhs,lhs): return cmp >= rhs and cmp <= lhs
score = select die
when 1: -2
when 2: -1
when between 3,4: 0
when 5: +1
when 6: +2
else: raise "invalid die roll %d " % roll
As a further (quite optional) enhancement, allow 'select'
keyword to be absent, and in this case, the 'when' statement
is evaulated as a boolean expression.
exit = when 0 == quantity: 'no exit'
when 1 == quantity: 'a door'
else: '%s doors' % quantity
Summary:
The proposal thus creates a flexible mechanism for avoiding
the excessive duplication of assignment and equality fragments
within a conditional assignment nest; it does so through a
new expression structure which, like the rest of Python, uses
indentation for structure.
This proposal thus provides the pratical benefit of a terinary
operator, while at the same time opening the door to a rich
(and quite readable) conditional assignment mechanism. As a
side effect, it could make lambda functions more powerful.
> Quite right. A switch/case statement isn't at issue for PEP 308,
> and I was incorrect to label this proposal as such -- switch/case
> is a block level construct which contains statements. I'm not
> proposing that.
I understand that. I (on autopilot) retyped what you wrote, but I
understood what you were suggesting. As I said, it is really beyond the
scope of PEP 308; it should be in another PEP.
> This proposal is for a select/when *expression* which is simply
> a generalization of a terinary operator, and equivalent to
> some of the "elif" like options on the table. So, this
> proposal fits right in with the spirit of the PEP.
It's something that could degenerate to a ternary (or trinary, but not
terinary) operator, but it in and of itself is a more generalized
construct and so is not appropriate for a PEP 308 vote. If you want to
suggest a generalized select/when (or whatever you want to call it) and
propose that, that's fine, but it would be for another PEP.
Take people who wanted to implement ternary operators in terms of a
special syntax for zero-argument lambdas and a new builtin; this
degenerates to a ternary (or can be used as one), but really deserved to
be suggested under another PEP; and, indeed, it was.
--
Erik Max Francis / m...@alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE
/ \ I like young girls. Their stories are shorter.
\__/ Thomas McGuane
Crank Dot Net / http://www.crank.net/
Cranks, crackpots, kooks, & loons on the Net.
Being a db-oriented person,
I use sql standard conditional constructs
both IF and CASE expressions on daily basis.
It is definitely not rocket-science support stuff.
But it'd sure help some people maintain routine stuff
in business app, most specifically people who try to
use python as a server-script engine à la ASP, PHP.
Any feedback from the PSP (and AL) user community...
François
>On Wed, Mar 05, 2003 at 02:14:06AM +0000, Dennis Reinhardt wrote:
>| The weakness is that Python has a "dangling else" ambiguity which requires
>| indentation to disambiguate (i.e. the if-else must occupy two lines
>| minimum).
>
>Why is this a weakness? I like indentation. I use Python exactly
>beacuse it uses indentation to show me structure. The biggest problem
>I have with all of the 'terinary' options is that they are
>single-line solutions.
>
>The only solution that the terinary operator needs to solve
>is a way to provide for conditional logic within an expression
>intead of forcing the programmer to use statements.
If you are literally building the source automatically by inserting
bits of expressions into a larger chunk of code (I assume that Zope is
doing this, and I also have some code which does this) then having to
obey indentation rules for the inserted expression is a nightmare. You
don't know what the indentation level was for the statement you are
inserting into when you write the expression, which may easily be
inserted into many different pieces of code.
Of course, this is a specialist issue and the difficulty of writing
code generators is not a good argument for making language design
decisions. Besides, if it became that serious an issue, someone could
always write a Python-source-manipulation library which automatically
obeyed indentation rules to preserve the intended meaning of
insertions. Not easy, but achievable.
So is there another argument?
Well - the programmer is not forced to do all block structure by
indentation in Python. There are aspects that are left to the
programmers judgement. For instance, you can already write...
if c : do_x; do_y; do_z
In an expression, structuring by indentation does not exist at all at
the moment. Structuring within expressions is done by precedence and
associativity rules, and by parentheses. If indentation is to be used
for structuring within expressions, then new indentation rules are
probably needed - something like Haskells offside rule (which I
mentioned recently in another thread).
But is it even natural to ALWAYS use indentation for a particular
structure in an expression? I don't think it is.
No-one would write a language which insists that basic arithmetic
operators are structured with indentation. This can be useful,
however, even with parentheses or precedence making the real decisions
- for instance...
a = ( ( (some_long_expression)
* (some_long_expression))
+ ( (some_long_expression)
* (some_long_expression)))
...but that's no reason to force it on everyone in every case.
While it is by no means as clear cut a case, I do believe essentially
the same logic applies to conditional operators. Indentation may be a
very useful thing in ensuring something is readable, but at the end of
the day that should be left to the individual programmers judgement.
Absolute dogmatic rules don't always make the right decision.
As it happens, I tend to think of the else problem in existing if
statements as a (very minor) wart. I see no problem with readability
in something like...
if b != 0 : print "a/b = ", a/b ;; else : print "div by zero"
(using ';;' as a hypothetical 'stronger' end-of-statement operator)
This would particularly be the case with many similar if-statements in
sequence - the vertical alignment between clauses can emphasize both
the pattern and the exceptions, and can dramatically help readability,
but that benefit is largely lost for a sequence of distinct multiline
clumps.
While I can do that in C++ (still keeping the braces, which I really
don't like to omit) I've lost that capability in Python. It's
certainly a very good trade overall, but I don't want to see even a
very minor wart replicated unnecessarily.
In a kind of 20/20 hindsight + personal preference thing, if I was
writing Python I'd have probably kept braces as an option for block
structuring when indentation didn't seem appropriate (or for those who
want to combine both) - just as Guido kept ';' as an optional
statement terminator. Lists and dictionaries would both use '[]', but
with an initial keyword to say which was which (or perhaps using the
colons in a dictionary to disambiguate). If braces were used for a
multi-line block, it would still have to obey indentation rules as
well.
I suspect that even Guido might be tempted if he were rewriting
Python, not so much to put an else on the same line but because a lot
of people complain about structuring by indentation from time to time.
Yes - there are even people (though emphatically NOT me) who see all
structuring by indentation as a wart.
--
steve at ninereeds dot fsnet dot co dot uk
';' is more of a statement separator than a terminator. From the Grammar
file:
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
and it should really only be used to seperate small statements (literally :)
> I suspect that even Guido might be tempted if he were rewriting
> Python, not so much to put an else on the same line but because a lot
> of people complain about structuring by indentation from time to time.
> Yes - there are even people (though emphatically NOT me) who see all
> structuring by indentation as a wart.
I somewhat doubt it. He may have other reasons for doing that (in the
hypothetical case) but not because of people complaining about the whitespace.
Allowing the use of braces while still enforcing indentation wouldn't seem
too much of an improvement to those people, and many, almost all in my
experience, quickly adapt and see the Light. I don't think Guido even thinks
about it, as he's not planning on redoing Python from scratch.
If I ever were to design my own language, I certainly would not use block
delimiters unless I really really had to, and even then I'd try to find an
alternative.
--
Thomas Wouters <tho...@xs4all.net>
Hi! I'm a .signature virus! copy me into your .signature file to help me spread!
Yup.
That said, I don't mind a x = conditional(c, a, b), becuase it looks
like a function. If people neseecarily have to make if-then-else
statements like this on one line, create that function. Heck, here it
is:
conditional.py:
def conditional(c, a, b):
if c:
return a
else:
return b
Done!
Look, I even tested it for you! :)
>>> from conditional import conditional
>>>
>>> x = conditional(1, 'True', 'False')
>>> print x
True
So there. No, go and vote "I reject all options". There is no point in
adding ugluness to a pretty language if that uglyness doesn't have a
real value, and this hasn't. If you want one line conditionals, now
you have them. :)
It is ternary, not terinary. If you are going to trash something I
like with name-calling opinions masqueraded as fact, please at least
spell it right. But I guess you do not want me to read your proposal.
[snip]
> In particular, this proposal rejects the rationale for 'terinary'
ternary
> operator as a way to trade horizontal screen realestate for
> vertical space; as this rationale is in direct opposition to
> the fundamental principle of readability.
How does 'C op1 b op2 c', when performing a conditional selection
operation, violate the 'fundamental principle of readibility',
whatever that is, any more than any other five-token expression, such
as 'a + b * c' or 'a <= b <= c'?
Terry J. Reedy
>On Wed, Mar 05, 2003 at 11:06:46AM +0000, Stephen Horne wrote:
>> just as Guido kept ';' as an optional statement terminator.
>
>';' is more of a statement separator than a terminator. From the Grammar
>file:
>
>simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
>
>and it should really only be used to seperate small statements (literally :)
Hmmm - that final [';'] looks like an optional terminator, even for
the final statement in the line, to me ;-) Of course, I really
wouldn't expect to see it used.
Once it's optional, the separator-or-terminator distinction really
doesn't make much difference though. IIRC the semicolon is a separator
rather than a terminator even in C. For instance...
if (condition)
{
statement;
/* there is an implicit null statement here */
}
... but it doesn't necessarily mean people *think* of it as a
separator e.g. they always put it at the end of the statement.
I remember an article about Ada, from back when it had the working
title of 'Green'. One of the famous algorithm guys (Dijkstra? - my
memory is straining) ripped apart their rationale for using
terminators rather than separators. They didn't change, though - and
he didn't make any particularly compelling argument for separators
that I remeber - he mostly just thought their rationale was bogus.
It was probably a little unfair, too. Ada was designed by committee,
and someone probably decided that every decision must have a written
rationale - a rationale like "it makes no real difference either way
so what the hell, I rolled I dice" probably wouldn't make it through a
review - unless it was late Friday afternoon after a pub lunch and
everyone wanted to get home early ;-)
In reality, most multilingual programmers aren't even aware that
semicolons are doing subtly different things in C and Ada.
>> I suspect that even Guido might be tempted if he were rewriting
>> Python, not so much to put an else on the same line but because a lot
>> of people complain about structuring by indentation from time to time.
>> Yes - there are even people (though emphatically NOT me) who see all
>> structuring by indentation as a wart.
>
>I somewhat doubt it.
Perhaps - I certainly doubt it would get into Python 3000 ;-)
> He may have other reasons for doing that (in the
>hypothetical case) but not because of people complaining about the whitespace.
>Allowing the use of braces while still enforcing indentation wouldn't seem
>too much of an improvement to those people
Proper indentation is good coding style in any block structured
language, whether it's enforced or not. Even where the compiler
doesn't use or enforce it, anyone who has to read or maintain your
source code is likely to bite your head off if the indentation is
confusing or misleading. I've seen cases where this almost literally
came true. Once or twice it was only the zits and greasy hair that
stopped me doing it myself ;-)
Yet the indentation issue is not just one that total newbie
programmers raise - experienced programmers sometimes raise it, and
some even continue to raise it when they are familiar with Python.
Some people really seem to miss the explicit '{' and '}' (or 'begin'
and 'end' or whatever). I've never quite understood why, but having
seen the debate run a couple of times I have accepted that to be a
failing of my imagination.
Maybe it's just familiarity - sometimes a surprisingly strong force.
For example, I kind of miss the '++' and '--' operators from C as a
convenient increment statement (though certainly not when used in
expressions), and I was very happy when '+=' and '-=' were added. But
the '*=', "/=", '&=', "|=" (and especially the "%=" and "**=") are
less frequently used and therefore less familiar, and sometimes seem
like a wart - even though they follow exactly the same principle.
I've usually been left with the feeling that there was a more
substantial point, though, even if I didn't quite get it.
>If I ever were to design my own language, I certainly would not use block
>delimiters unless I really really had to, and even then I'd try to find an
>alternative.
I'm not sure I understand what you mean by finding an alternative. An
alternative to '{' and '}'? Or a wider alternative avoiding any
explicit delimiting tokens, yet different to indentation?
If the former, I actually think ANSI BASIC has some nice features.
It's delimiters are almost full-fledged statements in themselves - for
example, a loop can optionally have either (or both) a precondition
and a postcondition using the same basic structure...
do [while condition]
...
loop [until condition]
This handles quite a few otherwise awkward cases without resorting to
'break', 'continue' or the Ada 'exit when condition;'.
Ada also has a nice feature in that you can say what you think your
ending (the procedure or function name, or just 'end while' or 'end
if') and the compiler checks whether you're right.
If you'd look for a non-delimiter solution, the only real alternative
I can think of is a continuation-based system - like using '\' to
continue statements over multiple lines. Which leads me to say -
"yuck!!!". I find multiline statements generally get that way by
containing big expressions, so I use extra brackets to avoid the '\' -
which brings us back, in principle, to delimiters!
Delimiters aren't really bad in principle, or else they wouldn't have
lasted this long in so many different languages. It's just that
indentation is usually even better - or else it wouldn't be considered
good style in languages that already require delimiters.
You are wrong on this point.
int main()
{
return 0
}
is not a valid C program.
- Anders
On Wed, Mar 05, 2003 at 09:38:21AM -0500, Terry Reedy wrote:
| ternary
Apologies. Just trying to get some attention, I didn't
mean to trash the ternary proposal; in fact, I'd like to
see a conditional expression make it into Python.
| > operator as a way to trade horizontal screen realestate for
| > vertical space; as this rationale is in direct opposition to
| > the fundamental principle of readability.
|
| How does 'C op1 b op2 c', when performing a conditional selection
| operation, violate the 'fundamental principle of readibility',
| whatever that is, any more than any other five-token expression, such
| as 'a + b * c' or 'a <= b <= c'?
In general, Python code tends to naturally use less an 80 columns
due to its use of line breaks and indentation to indicate scope.
As a result, Python tends to be a bit 'hoizontally slim' compared
to most languages, and I feel this enhances readability. For
example, the if/else statement structure requires at least one
line per option. In contrast, when a line goes past 80 columns
(in violation of the Python style guide) it is usually the result
of a complex expression. And, unlike the other operators out
there, this conditional expression is quite complicated due to
is branching behavior. Therefore, I would expect that usage of
a single-line ternary operator would, on average, increase the
'fatness' of Python code and, on average, increase the insidents
of 80 column violations.
So, while I agree we need a construct which allows for conditional
logic within an expression, I disagree that such a construct
should be a one-liner. I also think that a bulk of the opposition
on this list to a ternary expression is somehow related to
this stylistic argument; perhaps subconciously. And, as such,
I'd rather not have the baby (a conditional expression) thrown
out with the bathwater (one-line expressions).
On Tue, Mar 04, 2003 at 11:33:35PM -0800, Erik Max Francis wrote:
| I understand that. I (on autopilot) retyped what you wrote, but I
| understood what you were suggesting. As I said, it is really beyond the
| scope of PEP 308; it should be in another PEP.
Quoteth the PEP:
A natural extension of this syntax is to allow one
or more 'elif' parts:
(if <cond1>: <expr1> elif <cond2>: <expr2> ... else: <exprN>)
This will be implemented if the proposal is accepted.
| It's something that could degenerate to a ternary (or trinary, but not
| terinary) operator, but it in and of itself is a more generalized
| construct and so is not appropriate for a PEP 308 vote. If you want to
| suggest a generalized select/when (or whatever you want to call it) and
| propose that, that's fine, but it would be for another PEP.
|
| Take people who wanted to implement ternary operators in terms of a
| special syntax for zero-argument lambdas and a new builtin; this
| degenerates to a ternary (or can be used as one), but really deserved to
| be suggested under another PEP; and, indeed, it was.
Yes, but this isn't a separate item. The proposal has two
differences:
1. It requires that each part of the conditional be on its
own line and properly indented.
(if <cond1>: <expr1>
elif <cond2>: <expr2>
...
else: <exprN>)
or, in this proposal,
select when <cond1>: <expr1>
when <cond2>: <expr2>
...
else: <exprN>
This aspect follows from the current Python style, which
favors new lines and indentation to determine scope.
2. It provides a "defaulting" mechanism so that the variable
tested (lhs) doesn't have to be duplicated again and again.
select <lhs>
when <op1>? <rhs1>: <expr1>
when <op2>? <rhs2>: <expr2>
...
else: <exprN>
This construct is similar to SQL's CASE/SELECT and a
minor (but essentail) improvement on the syntax for
the case where <lhs> is duplicated again and again.
Neither of these differences make it a 'different PEP'
Best,
Clark
>please at least spell it right.
I, for one, don't care how bad someones spelling is as long as I can
read it.
>How does 'C op1 b op2 c', when performing a conditional selection
>operation, violate the 'fundamental principle of readibility',
>whatever that is, any more than any other five-token expression, such
>as 'a + b * c' or 'a <= b <= c'?
Here, I absolutely agree with you - I see no reason to force
linebreaks in expressions - readability is best served by human
judgement, not absolute rules.
If I want to write, for example...
a = (if (b != 0) then a/b else 1000)
+ (if (d != 0) then c/d else 1000)
+ (if (h != 0) then g/h else 1000))
... then readability is best served by keeping each conditional on a
single line so that vertical alignment can emphasize the pattern.
That said, I think that some form of 'select' could have merit - but
as an alternative to, rather than a replacement for, a simpler
conditional expression notation.
OK - I'm surprised, but can't be bothered looking up the standard,
especially as I'm probably just getting confused with the comma
operator (which is *effectively* a separator, being an infix
operator).
I agree. It seems to me that a good select statement (not some
crippled one like C's switch) could be very useful. I don't see the
suggested syntax as a particulary good solution for PEP 308-type
problems, but for other uses.
Both of these are attempts to deal with some of the ugliness of
if/elif/else constructs. Is there some better general solution out
there?
>On Wed, 5 Mar 2003 16:34:21 +0100, "Anders J. Munch"
><ande...@dancontrol.dk> wrote:
>
>>You are wrong on this point.
>
>OK - I'm surprised, but can't be bothered looking up the standard,
>especially as I'm probably just getting confused with the comma
>operator (which is *effectively* a separator, being an infix
>operator).
Oops - I think I just figured it out... There was definitely a
language I used where you'd get a null statement by having a semicolon
after the last statement of a block (not that anyone cared), and now -
I think it was Pascal.
I can't believe I confused Pascal and C !!!
Or am I still wrong?
> On Wed, 5 Mar 2003 12:43:05 +0100, Thomas Wouters <tho...@xs4all.net>
> wrote:
> >On Wed, Mar 05, 2003 at 11:06:46AM +0000, Stephen Horne wrote:
> >> just as Guido kept ';' as an optional statement terminator.
> >';' is more of a statement separator than a terminator. From the Grammar
> >file:
> >simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
> Hmmm - that final [';'] looks like an optional terminator, even for
> the final statement in the line, to me ;-) Of course, I really
> wouldn't expect to see it used.
Well, you can add whitespace between the statement and the newline... does
that make whitespace an 'optional terminator' too ? :-) It might seem as a
silly semantic issue, but there is definately a difference between a ';' in
C and Perl et al, and in Python. I see the final ';' above more as a
consistency feature (which is important in Python, at least to me.) And
having an "optional terminator" is just silly, it either terminates or it
doesn't, and if it's optional it doesn't really terminate :)
> Once it's optional, the separator-or-terminator distinction really
> doesn't make much difference though. IIRC the semicolon is a separator
> rather than a terminator even in C. For instance...
> if (condition)
> {
> statement;
> /* there is an implicit null statement here */
> }
No, sorry. In C, the semicolon is a terminator, not a separator. For
instance:
i++
+j;
is something completely different than
i++;
+j;
(And to make things even more fun,
i+
++j;
is not what it seems to be; this will post-inc i, not pre-inc j, because of
C's syntax rules.) If the semicolon was really just a separator, C would be
able to tell when a statement (that consists of just an expression) ended
without them. In Python, statements are terminated by a newline.
> Proper indentation is good coding style in any block structured
> language, whether it's enforced or not. Even where the compiler
> doesn't use or enforce it, anyone who has to read or maintain your
> source code is likely to bite your head off if the indentation is
> confusing or misleading. I've seen cases where this almost literally
> came true. Once or twice it was only the zits and greasy hair that
> stopped me doing it myself ;-)
I've seen worse. One project I'm involved in had a function to open a
directory and read the entries looking for all files fulfilling a requirement.
As usual, it skipped files with leading dots. However, something must have
gone wrong, because the entire function was #if 0'd out, and replaced by a
function that popen()'d a perl process to do exactly the same thing. Now
this wasn't a terribly frequent operation, but still frequent enough for me
to be scared about executing perl each time :) So I tried to figure out what
was wrong with the disabled, pure C code, and found it after a single pass
of indent. This was the code before the indent:
if (line[0] == '.');
continue;
Isn't C luverly ? :) For those who don't know C, what the above statement
does should be obvious, as it's nearly the same as the Python. Except that
in C, an 'if' suite isn't marked by a colon and an indented block, but
either by curly braces, or by being exactly one line. so
if (condition) { code(); }
and
if (condition) code();
do the same thing. The problem with the above example was the semicolon
after the if(), which basically turned the block into:
if line[0] == '.': pass
continue
> Some people really seem to miss the explicit '{' and '}' (or 'begin'
> and 'end' or whatever). I've never quite understood why, but having
> seen the debate run a couple of times I have accepted that to be a
> failing of my imagination.
There are also lots of people who can't seem to like Python, or really
prefer Perl. I really can't imagine that (I write Perl for a living,
nowadays, and I really wish I wasn't) but I can accept that they don't like
Python. Python apparently can't cater to everyone (but yes, I do wonder
why :) I've heard maybe one compelling reason not to use indentation,
embedding code into other markup, but having written Perl that uses HTML
templates to generate JavaScript that generate HTML tables for inside
overlays (and in particular, debugging those) I now consider that a feature.
Other uses for blocks can be solved using '# {' and '# }', in my eyes.
> >If I ever were to design my own language, I certainly would not use block
> >delimiters unless I really really had to, and even then I'd try to find an
> >alternative.
> I'm not sure I understand what you mean by finding an alternative. An
> alternative to '{' and '}'? Or a wider alternative avoiding any
> explicit delimiting tokens, yet different to indentation?
No, an alternative to solve the problem that would otherwise be solved by
not making indentation mark blocks. E.g. issues with embedding the code into
other markup. I would rather solve that in the embedding than in the
language.
> If you'd look for a non-delimiter solution, the only real alternative
> I can think of is a continuation-based system - like using '\' to
> continue statements over multiple lines. Which leads me to say -
> "yuck!!!". I find multiline statements generally get that way by
> containing big expressions, so I use extra brackets to avoid the '\' -
> which brings us back, in principle, to delimiters!
On the other end of the spectrum, I find that whenever I think I need a \, I
go back and look at the code, and decide another way with a shorter 'if' or
one that continues naturally (like braces) is clearer, and I end up with (to
me) nicer code. This often involves more objects and more features, without
too much extra effort. (I find I do that a lot nowadays, incremental
software development by running several cycles (including tests, of course)
before releasing the product to user-testing. :)
> Delimiters aren't really bad in principle, or else they wouldn't have
> lasted this long in so many different languages. It's just that
> indentation is usually even better - or else it wouldn't be considered
> good style in languages that already require delimiters.
Don't forget that programming languages are still in development. They are
quite new, and also have to struggle to keep in pace with hardware
development. Considerations that were true for such languages as FORTRAN or
C, such as ease and efficacy of parsing, compiler-writing and resulting
code, are no longer an issue for a language as, say, Python or Perl or even
language that share part of the domain, such as Java and C++.
And also don't forget that languages are designed by humans, and many
designers build on the features that they are familiar and comfortable with
-- even if they aren't terribly efficient. Even Python! Python really isn't
that innovative as a language, it's just very well put together, both in
design and in implementation. Just look at how strained the ternary operator
proposals all look; the idea comes from C and Perl (for many people, at
least) and so the tendency is to make the syntax look like C -- and all
other syntactic suggestions look odd. (Or is that just me ? :)
> > OK - I'm surprised, but can't be bothered looking up the standard,
> > especially as I'm probably just getting confused with the comma
> > operator (which is *effectively* a separator, being an infix
> > operator).
>
> Oops - I think I just figured it out... There was definitely a
> language I used where you'd get a null statement by having a semicolon
> after the last statement of a block (not that anyone cared), and now -
> I think it was Pascal.
>
> I can't believe I confused Pascal and C !!!
>
> Or am I still wrong?
No, you're right. The semicolon is a separator in Pascal
and a terminator in C. (And a comment-introducer in Lisp. :-) )
--
Gareth McCaughan Gareth.M...@pobox.com
.sig under construc
> Oops - I think I just figured it out... There was definitely a
> language I used where you'd get a null statement by having a semicolon
> after the last statement of a block (not that anyone cared), and now -
> I think it was Pascal.
Yes, Pascal does that. This used to cause hours of fun in the old
days, as C and Pascal programmers "discussed" the True Purpose Of
Semicolons. ("They're separators, C-weenie!" "They're terminators,
Pascal luser!")
Des
--
Dr Des Small / Scientific Programmer/ School of Mathematics /
University of Bristol / University Walk / Bristol BS8 1TW / United
Kingdom / Word falling / Image falling
> mi...@pitt.edu (Michele Simionato) writes:
>
>> This voting procedure forces me to write what I like the best (even
>> in the 'reject' case, I must check the last hated expression). I
>> have no way to express what I dislike the most.
>
> I have now voted, and no longer really care, but yes, I agree that
> this was the most annoying aspect of the voting system. Not being able
> to say how much I *loathe*
>
> (if c: x else: y)
>
> was a definite lack for me.
Yeah, I had the feeling when I saw that, that it was proposed just as
a way of killing the whole idea ;-)
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com
>On Wed, Mar 05, 2003 at 02:45:53PM +0000, Stephen Horne wrote:
>
>> On Wed, 5 Mar 2003 12:43:05 +0100, Thomas Wouters <tho...@xs4all.net>
>> wrote:
>
>> >On Wed, Mar 05, 2003 at 11:06:46AM +0000, Stephen Horne wrote:
>> >> just as Guido kept ';' as an optional statement terminator.
>
>> >';' is more of a statement separator than a terminator. From the Grammar
>> >file:
>
>> >simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
>
>> Hmmm - that final [';'] looks like an optional terminator, even for
>> the final statement in the line, to me ;-) Of course, I really
>> wouldn't expect to see it used.
>
>Well, you can add whitespace between the statement and the newline... does
>that make whitespace an 'optional terminator' too ? :-)
Nope - you can add whitespace anywhere, not just after a statement. If
the semicolon is there you know the statement has ended.
> It might seem as a
>silly semantic issue, but there is definately a difference between a ';' in
>C and Perl et al, and in Python.
Absolutely - no argument there.
> I see the final ';' above more as a
>consistency feature (which is important in Python, at least to me.) And
>having an "optional terminator" is just silly, it either terminates or it
>doesn't, and if it's optional it doesn't really terminate :)
Not really - it means you can spell 'end-of-statement' three ways - a
semicolon on its own, a NEWLINE on its own, or a semicolon followed by
a NEWLINE. It's optional in the sense that there are other choices.
The last of those three choices is pretty pointless, of course, but it
does no harm.
>No, sorry. In C, the semicolon is a terminator, not a separator. For
>instance:
Yes - my mistake, as explained elsewhere.
> i++
> +j;
Though this is irrelevant as you have no separator *or* terminator,
and no-one was proposing that the compiler should mind-read to
separate one statement from another.
When I was saying that optionalness of the semicolon makes the
difference between separation and termination, I was saying that
(forgive me if my Pascal is rusty) the following are equally clear...
{ example 1 - termination }
begin
a := b;
c := d;
end
{ example 2 - separation }
begin
a := b;
c := d
end
Note that there is always a semicolon between the 'a := b' and the 'c
:= d' because this is how Pascal knows it is dealing with two separate
statements, but when the 'end' terminates the block the semicolon can
(depending on the language) be considered redundant.
>I've seen worse. One project I'm involved in had a function to open a
>directory and read the entries looking for all files fulfilling a requirement.
>As usual, it skipped files with leading dots. However, something must have
>gone wrong, because the entire function was #if 0'd out, and replaced by a
>function that popen()'d a perl process to do exactly the same thing. Now
>this wasn't a terribly frequent operation, but still frequent enough for me
>to be scared about executing perl each time :) So I tried to figure out what
>was wrong with the disabled, pure C code, and found it after a single pass
>of indent. This was the code before the indent:
>
> if (line[0] == '.');
> continue;
<big grin>
The trouble with this is that the semicolon is often DELIBERATELY used
to terminate a block structure early like that. Not with if, but often
with while or for.
A fairly common would be something like...
void strcpy_alike (char *p_Dest, char *p_Src)
{
while ((*p_Dest++ = *p_Src++) != 0);
}
<loud retching noises>
Anyway, newbies can see things like this and start thinking that the
'while (condition)' is a kind of statement in itself, and think it
always needs a semicolon - and the compiler is, of course, perfectly
happy with this!
>I've heard maybe one compelling reason not to use indentation,
>embedding code into other markup
There is this, to a point. But at the end of the day, source code is
for people to read and write.
>No, an alternative to solve the problem that would otherwise be solved by
>not making indentation mark blocks. E.g. issues with embedding the code into
>other markup. I would rather solve that in the embedding than in the
>language.
I see - I think I mentioned having a library for manipulating source
(and preserving intended semantics) in another post somewhere, so this
does make sense to me.
>Just look at how strained the ternary operator
>proposals all look; the idea comes from C and Perl (for many people, at
>least) and so the tendency is to make the syntax look like C -- and all
>other syntactic suggestions look odd. (Or is that just me ? :)
In my mindset, I like unary (prefix or postfix) and binary (infix)
operators. Outside of that, I start getting nervous - I prefer more
function-like syntaxes even if there is shortcircuiting, and I
certainly want a leading keyword to tell me that a conditional
operator is coming.
The C ternary operator always seemed somehow wrong to me anyway.
I still haven't voted on PEP308 because I'm having some trouble
picking. One near-favorite is...
if c then x else y
...though that still falls foul of the 'no more than binary' rule.
The other is something like...
select ( c1 : x, c2 : y, z )
...or even just...
if (c, x, y)
... but I don't think any of those is an official option anyway, so
they're *very* unlikely to win.
I've seen languages where no operators could shortcircuit, and I've
seen plenty of languages where functions use lazy evaluation. In
Python, I'd be surprised if the expression '0 * x' was shortcircuited
even though it uses an operator and the right-hand-side is redundant.
Therefore, in my view, the idea that function calls imply no
shortcircuiting whereas operators imply shortcircuiting is simply
wrong.
But yes, you are right - even the options that I like feel strange in
one way or another. Only the if function seems completely natural
(because I've used it so much in spreadsheets, mainly - and yes, they
shortcircuit it), but that annoys quite a few others.
Ok.
a = ((when b != 0: a/b
else: 1000)
+ (when d != 0: c/d
else: 1000)
+ (when h != 0: g/h
else: 1000))
Which I admit isn't very pretty. However, if you assume that
in the select/when proposal a missing else clause causes
non-matches to evaluate to None, you get...
a = ( ((when b != 0: a/b) or 1000))
+ ((when d != 0: c/d) or 1000))
+ ((when h != 0: g/h) or 1000)))
I guess this is one extra level of parenthesis... but then
again the if/then proposal could be limited to such a scope
(not having an else).
| That said, I think that some form of 'select' could have merit - but
| as an alternative to, rather than a replacement for, a simpler
| conditional expression notation.
Hmm. As soon as you add "else" to the if clause, I think
it should be time to consider how to make it more flexible.
Best,
Clark
def sum(lst):
res = 0
for itm in lst:
res += itm
return res
def div(numerator, denominator, ifzero = None):
if denominator != 0: return numerator/denominator
return ifzero
a = sum([div(x,y) for x,y in ((a,b),(c,d),(g,h))])
It isn't that hard. Also, for my dynamically-generated SQL I spend
a good amount of effort making sure it looks nice. Nothing worse
than a bug in jumbled-into-a-single-line-auto-generated code. ;)
| So is there another argument?
|
| Well - the programmer is not forced to do all block structure by
| indentation in Python. There are aspects that are left to the
| programmers judgement. For instance, you can already write...
|
| if c : do_x; do_y; do_z
I don't use (nor do I miss) the semi-colon in my code...
| No-one would write a language which insists that basic arithmetic
| operators are structured with indentation. This can be useful,
| however, even with parentheses or precedence making the real decisions
| - for instance...
|
| a = ( ( (some_long_expression)
| * (some_long_expression))
| + ( (some_long_expression)
| * (some_long_expression)))
|
| ...but that's no reason to force it on everyone in every case.
Yes, but a conditional is unlike these binary operators,
it has, to quote Dannis Reinhardt, a 'dangling else' ambiguity.
And rather than making an ugly "endif" construct, I'd rather
force indentation for the conditional expression.
| As it happens, I tend to think of the else problem in existing if
| statements as a (very minor) wart. I see no problem with readability
| in something like...
|
| if b != 0 : print "a/b = ", a/b ;; else : print "div by zero"
|
| (using ';;' as a hypothetical 'stronger' end-of-statement operator)
|
You don't !? In a word, *ouch*
| While I can do that in C++ (still keeping the braces, which I really
| don't like to omit) I've lost that capability in Python. It's
| certainly a very good trade overall, but I don't want to see even a
| very minor wart replicated unnecessarily.
I don't see Python's indentation as a wart; I see it as an
essential aspect which making Python code easy to read
and understandable without distracting indicators.
| I suspect that even Guido might be tempted if he were rewriting
| Python, not so much to put an else on the same line but because a lot
| of people complain about structuring by indentation from time to time.
| Yes - there are even people (though emphatically NOT me) who see all
| structuring by indentation as a wart.
And lucky for them there are lots of languages out there,
such as Perl, Ruby or even Java/C#, which suit their tastes
more closely. I'd rather go without a conditional expression
than have one which uses parenthesis or god-awful "endif"
ickyness instead of relying upon good-ole whitespace.
Winks,
Clark
A true ternary C op a po b has no such ambiguity. Every op must be
matched by a following po. Every po matches the nearest preceding
unmatched op. Just as with (), [], etc. Possible ambiguity arises in
conditional statement trees because 'else: pass' is allowed to be
omitted. But conditional expressions *must* evaluate to something in
all branched of the logic tree.
Terry J. Reedy
So, in Python:
[1, 2, 3,]
[1, 2, 3]
Is the comma a terminator or a separator?
[...]
> A fairly common would be something like...
>
> void strcpy_alike (char *p_Dest, char *p_Src)
> {
> while ((*p_Dest++ = *p_Src++) != 0);
> }
>
> <loud retching noises>
A bit off-topic, but imho a minor style change improves this
dramatically:
while ((*p_Dest++ = *p_Src++) != 0)
;
With the semicolon all lonesome on the next line, it is very
noticeable; it shouts "this statement intentionally left blank".
Now and then I use 'pass' in Python in a similar way:
def nop():
"""Do nothing."""
pass # not required by the syntax
(Also useful in empty class definitions that have docstrings.)
[...]
> I've seen languages where no operators could shortcircuit, and I've
> seen plenty of languages where functions use lazy evaluation. In
> Python, I'd be surprised if the expression '0 * x' was shortcircuited
> even though it uses an operator and the right-hand-side is redundant.
[...]
It's not redundant at all: 0*1 and 0*[] yield objects of different
types; if x is an instance of a user-defined vector class, the
multiplication should return the zero vector, not 0; and so forth.
The second operand must be evaluated to achieve this polymorphism.
--
Steven Taschuk stas...@telusplanet.net
Receive them ignorant; dispatch them confused. (Weschler's Teaching Motto)
> OK - I'm surprised, but can't be bothered looking up the standard,
> especially as I'm probably just getting confused with the comma
> operator (which is *effectively* a separator, being an infix
> operator).
He's definitely right. Maybe you're thinking of Pascal, in which the
final semicolon could be suppressed at the end of some blocks? (I
haven't touched Pascal in many, many years, so I don't remember the
details.)
--
Erik Max Francis / m...@alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE
/ \ It's a man's world, and you men can have it.
\__/ Katherine Anne Porter
The laws list / http://www.alcyone.com/max/physics/laws/
Laws, rules, principles, effects, paradoxes, etc. in physics.
>| ...but that's no reason to force it on everyone in every case.
>
>Yes, but a conditional is unlike these binary operators,
>it has, to quote Dannis Reinhardt, a 'dangling else' ambiguity.
>And rather than making an ugly "endif" construct, I'd rather
>force indentation for the conditional expression.
A dangling else ambiguity is a feature of a few *particular* choices
of conditional expression syntax - it is not a fundamental feature of
all possible syntaxes and many of the proposals simply don't have this
problem.
>
>| As it happens, I tend to think of the else problem in existing if
>| statements as a (very minor) wart. I see no problem with readability
>| in something like...
>|
>| if b != 0 : print "a/b = ", a/b ;; else : print "div by zero"
>|
>| (using ';;' as a hypothetical 'stronger' end-of-statement operator)
>|
>
>You don't !? In a word, *ouch*
Really. It is perfectly readable. Not 'beautiful', but that's mainly
because I'm starting from an existing syntax that isn't designed to
work this way and because I had to invent a rather ugly hypothetical
operator to make it work.
Even so, it's not meant to be art.
The single line example standing alone rather misses the point,
though. The benefit comes when there are a sequence of similar lines -
as I've mentioned earlier, vertical alignment can emphasise patterns
between those lines. Split each of those lines over two, and perhaps
add a blank line after each else line, and the patterns start to get
less clear.
I've had trouble finding a real example - which emphasises how
exceptional and unimportant the issue is, really - but I did find the
following in a C++ program...
if (Red < 0) { Red = 0; } else if (Red > 255) { Red = 255; }
if (Green < 0) { Green = 0; } else if (Green > 255) { Green = 255; }
if (Blue < 0) { Blue = 0; } else if (Blue > 255) { Blue = 255; }
I don't think any of the more spaced out alternatives would be as
clear.
That said, it's only my distaste for the C ternary operator that
stopped me writing...
Red = (Red < 0) ? 0 : ((Red > 255) ? 255 : Red );
Green = (Green < 0) ? 0 : ((Green > 255) ? 255 : Green);
Blue = (Blue < 0) ? 0 : ((Blue > 255) ? 255 : Blue );
...and it wouldn't take much more repetition before I'd write a
function to do each limiting step for me. There's no doubt that...
Limit (Red, 0, 255);
Limit (Green, 0, 255);
Limit (Blue, 0, 255);
...would be even clearer still, though for just three repeats I'd
prefer not to separate out that detail.
>| While I can do that in C++ (still keeping the braces, which I really
>| don't like to omit) I've lost that capability in Python. It's
>| certainly a very good trade overall, but I don't want to see even a
>| very minor wart replicated unnecessarily.
>
>I don't see Python's indentation as a wart; I see it as an
>essential aspect which making Python code easy to read
>and understandable without distracting indicators.
I didn't say indentation is a wart. I said that the inability to get a
whole if statement, else part included, on one line - in the
exceptional case when it is useful - is a wart. An extremely minor
wart, but IMO a wart nonetheless.
It's a matter of having alternatives available for those cases when
they are beneficial. Human judgement is superior to dogmatic rules.
IMO the most readable code results when a responsible and experienced
programmer has the freedom to apply that experience - the language
should be flexible enough to support that.
>| I suspect that even Guido might be tempted if he were rewriting
>| Python, not so much to put an else on the same line but because a lot
>| of people complain about structuring by indentation from time to time.
>| Yes - there are even people (though emphatically NOT me) who see all
>| structuring by indentation as a wart.
>
>And lucky for them there are lots of languages out there,
>such as Perl, Ruby or even Java/C#, which suit their tastes
>more closely.
I tend to agree with you, except that structuring by indentation is
far from the only feature of Python that a programmer might like. If
everyone who considered even one Python feature harmful were to
abandon Python, there'd probably be no-one left - even Guido has
regretted a few past decisions.
> I'd rather go without a conditional expression
>than have one which uses parenthesis or god-awful "endif"
>ickyness instead of relying upon good-ole whitespace.
Parentheses are usually recognised as a way of making expressions
*more* readable, so I don't really know why you dislike them for
conditional expressions. But it's largely irrelevant anyway. Having a
conditional expression that works on a single line does not imply
having parentheses or an 'endif'. "c then a else b", for instance,
does not need linebreaks, indentation, parentheses or an endif.
The option to use indentation to structure conditional expressions
(depending on the specific syntax chosen) would probably be a good
thing - certainly novel for Python expressions, but if any syntax
deserves an Haskell-like offside rule conditional expressions are it -
but forcing the syntax to use multiple lines is unnecessary.
> a = ((when b != 0: a/b
> else: 1000)
> + (when d != 0: c/d
> else: 1000)
> + (when h != 0: g/h
> else: 1000))
>
>Which I admit isn't very pretty.
I wouldn't really complain that much about this example - my point is
mainly about the validity of the preference. After all, a conditional
doesn't need to get all that complex and you need multiple lines
anyway.
> However, if you assume that
>in the select/when proposal a missing else clause causes
>non-matches to evaluate to None, you get...
>
> a = ( ((when b != 0: a/b) or 1000))
> + ((when d != 0: c/d) or 1000))
> + ((when h != 0: g/h) or 1000)))
>
>I guess this is one extra level of parenthesis... but then
>again the if/then proposal could be limited to such a scope
>(not having an else).
The reason I dislike this has nothing to do with parentheses - it's
keeping a part of the old and/or paradigm, and in particular it keeps
the main 'bug' in the and/or paradigm - i.e.
(when true : None) or 1000
evaluates to 1000 - not None.
It's an improvement in that it 'reads better' than the and/or paradigm
but, IMO, it's not enough of an improvement.
But getting back to the point, just because you've used the 'or'
operator to express the 'else' part does not change the fact that
you've put each conditional on a single line. You've spelled it
differently, but you've structured and formatted it exactly the same
way that I did ;-)
> def sum(lst):
> res = 0
> for itm in lst:
> res += itm
> return res
>
> def div(numerator, denominator, ifzero = None):
> if denominator != 0: return numerator/denominator
> return ifzero
>
> a = sum([div(x,y) for x,y in ((a,b),(c,d),(g,h))])
I'd personally keep your div, but replace the rest with...
temp = ((a,b), (c,d), (g,h))
reduce (operator.add, [div(x,y) for x,y in temp])
But not always. Creating lists of tuples purely to exploit list
comprehensions etc. can easily distract from the real intention of the
code. It could depend on how those variables are related, for
instance, or where they came from. And of course, I wouldn't
necessarily want to apply the same operator on the LHS of each line -
it could just easily have been...
a = (if (b != 0) then a/b else 1000)
* ( (if (d != 0) then c/d else 1000)
+ (if (h != 0) then g/h else 1000)))
Sorry.
> Nick Vargish fed this fish to the penguins on Monday 03 March 2003
> 08:07 am:
> > It's confusing that I can list three syntax options, and either accept
> > or reject each. So, should I be a positivist, and vote in favor of all
> > the 'C then x else y' variants? Should I be negativist, and vote
> > against the forms I dislike?
> Read it closely -- reject doesn't apply to the forms you dislike, it
> only means "I prefer no change, but if a change /is/ going to be voted
> into place, I'd prefer it to be this form"
Yah, you right. That just backs up my original proposition -- the
ballot is confusing.
Nick
--
# sigmask.py || version 0.2 || 2003-01-07 || Feed this to your Python.
print reduce(lambda x,y:x+chr(ord(y)-1),'Ojdl!Wbshjti!=obwAqbusjpu/ofu?','')
>Quoth Stephen Horne:
> [...]
>> When I was saying that optionalness of the semicolon makes the
>> difference between separation and termination, [...]
>
>So, in Python:
> [1, 2, 3,]
> [1, 2, 3]
>Is the comma a terminator or a separator?
Same thing. With either semicolons for (at least Pascal) statements
and commas in the above lists, the most pragmatic answer is 'who
cares'. Of course I tend to see commas as separators and find your top
example strange, and of course I might well see semicolons the same
way if I hadn't used them as terminators in several other languages.
> while ((*p_Dest++ = *p_Src++) != 0)
> ;
I'm not sure. With modern compilers, using side effects like this is
IMO inherently bad - without the side-effects the loop has no purpose.
So while your right about the 'this line intentionally left blank'
effect, I still wouldn't use it myself. This style of code had value
when C was created (before decent optimisers had been developed), but
IMO it's had its day.
>It's not redundant at all: 0*1 and 0*[] yield objects of different
>types; if x is an instance of a user-defined vector class, the
>multiplication should return the zero vector, not 0; and so forth.
>The second operand must be evaluated to achieve this polymorphism.
Of the mistakes I've made recently, this is certainly the most
annoying. Damn.
Thanks. I just learned more Python. ;)
Clark
Why, surely this is an important theoretical point! How can we
say we know Python if we don't even know whether its commas are
separators or terminators?!
After donning my holy war hat (to banish the thought that these
terms are not a disjoint partition of the marks in question), I
see they're definitely terminators in tuples, but probably
separators elsewhere.
> [...] Of course I tend to see commas as separators and find your top
> example strange, and of course I might well see semicolons the same
> way if I hadn't used them as terminators in several other languages.
Did you see semicolons thus when you started programming? They're
separators in all the natural languages which use them, afaik.
I agree a final comma is strange in a one-line list such as
[1, 2, 3,], but as pointed out in another thread a little while
back, it's very handy when the list is long:
spam = [
a_big_long_expression,
another_big_long_expression,
a_third_big_long_expression,
]
The superfluous final comma makes this list easier to edit; no
puncutation adjustments needed when moving items to and fro. Good
style, imho.
> > while ((*p_Dest++ = *p_Src++) != 0)
> > ;
>
> I'm not sure. With modern compilers, using side effects like this is
> IMO inherently bad - without the side-effects the loop has no purpose.
> So while your right about the 'this line intentionally left blank'
> effect, I still wouldn't use it myself. This style of code had value
> when C was created (before decent optimisers had been developed), but
> IMO it's had its day.
Hm. How about a case like this?
def consume(iterator, sentinel):
"""Consume elements from iterator up to and including
first occurrence of sentinel, or end of stream.
"""
try:
while it.next() != sentinel:
pass
except StopIteration:
pass
(Could be useful for error recovery in parsers, for example.)
--
Steven Taschuk w_w
stas...@telusplanet.net ,-= U
1 1
>The superfluous final comma makes this list easier to edit; no
>puncutation adjustments needed when moving items to and fro. Good
>style, imho.
I agree - occasionally, I've run the equivalant of one of those
through an editiors sort and forgot that the (previously) last line
didn't have a comma. Annoying.
>Hm. How about a case like this?
>
> def consume(iterator, sentinel):
> """Consume elements from iterator up to and including
> first occurrence of sentinel, or end of stream.
> """
> try:
> while it.next() != sentinel:
> pass
> except StopIteration:
> pass
>
>(Could be useful for error recovery in parsers, for example.)
True - there is little point getting all extremist even over
side-effects, and I write something like this from time to time - as
well as the short-circuiting logic used to run a sequence up to the
first error (each function having an error-indicating return value and
side-effects to do the real job).
Mostly, the name is a big help.
I tend to dislike '++' in C more than perhaps I should (and more than
the 'next' function above) because the C standard does not guarentee
when the postincrement is done - it could be immediately when the
value is evaluated, it could be after the whole expression containing
it is fully evaluated, or it could be any time in between. Which means
that if you refer to the same variable twice in the expression, and
the first has a postincrement, you simply don't know what value the
second reference will give. This is quite easy to do by accident, and
many programmers don't even know the ambiguity exists.
That doesn't happen with a function, and can't happen at all in
Python.
An excellent point. (And one I have been bitten by.)
[...]
> That doesn't happen with a function, and can't happen at all in
> Python.
Certainly Python's guaranteed evaluation and execution order is
very comfortable. There is the occasional oddity:
d = {}
i = 3
i = d[i] = i+1
has a surprising (to me) result. But this isn't good style anyway.
--
Steven Taschuk stas...@telusplanet.net
Every public frenzy produces legislation purporting to address it.
(Kinsley's Law)
>Certainly Python's guaranteed evaluation and execution order is
>very comfortable. There is the occasional oddity:
> d = {}
> i = 3
> i = d[i] = i+1
>has a surprising (to me) result. But this isn't good style anyway.
I wondered what you were talking about - until I noticed that...
>>> d={}
>>> i=3
>>> i=d[i]=i+1
>>> i
4 <- this was expected
>>> d[i]
4 <- this was expected
>>> d
{4: 4} <- pardon? - why not {3: 4}
I'm not sure I understand it, but I imagine it has to do with '='
being n-ary (n >= 2) non-associative (rather than binary
right-associative). Maybe the assigns are done left-to-right, even
though the rightmost item is the source and must be evaluated first?
Yes, '=' is a statement, not an expression like in many other languages, and
the chained version is a special case of it, for convenience. The simple
example of
a = b = c = d
would in C be parsed as
a = (b = (c = d))
and executed innermost-first, but in Python, it's more like
(a, b, c) = (d,)*3
(Not quite, but close enough. Use the 'dis' module to see what it really
does :) This does, however, assign from left to right. But you should not
rely on the order! You could call this a wart, but it doesn't make real
sense to change it the other way 'round either, except if you're thinking of
assignment the wrong way 'round anyway. :) And besides, it has a good side
too.. It stops people from writing code like:
i = d[i] = i+1
Evil-wink'ly y'rs,
> I'm not sure I understand it, but I imagine it has to do with '='
> being n-ary (n >= 2) non-associative (rather than binary
> right-associative). Maybe the assigns are done left-to-right, even
> though the rightmost item is the source and must be evaluated first?
Yes, it's because Python evaluates changed assignments from left to
right.
--
Erik Max Francis / m...@alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE
/ \ History is a bucket of ashes.
\__/ Carl Sandburg
HardScience.info / http://www.hardscience.info/
The best hard science Web sites that the Web has to offer.
Exactly.
Now that I look, I see that the language reference (6.3) has a
nice example of a related gotcha:
x = [0, 1]
i = 0
i, x[i] = 1, 2
print x
Heh. All good material for an obfuscated Python contest.
--
Steven Taschuk stas...@telusplanet.net
"Its force is immeasurable. Even Computer cannot determine it."
-- _Space: 1999_ episode "Black Sun"