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

Curious assignment behaviour

0 views
Skip to first unread message

Dale Strickland-Clark

unread,
Oct 8, 2001, 7:55:28 AM10/8/01
to
I observe that the folowing works as some might expect:

x = y = 5

Assigns 5 to both x and y.

However the expression:

y = 5

does not yeild 5

>>> print y = 5
Traceback ( File "<interactive input>", line 1
print y = 5
^
SyntaxError: invalid syntax
>>>

So this is obviously a gludge in assignment.

I'd be much happier if assignment yeilds the value assigned, as it
does in C (I believe). It could then be used universaly.

Also, where is this curious behaviour documented? 6.3 of the Language
Ref makes no reference to it. (Go on. Prove me wrong!)

Thanks.
--
Dale Strickland-Clark
Riverhall Systems Ltd

Chris Gonnerman

unread,
Oct 8, 2001, 8:22:18 AM10/8/01
to pytho...@python.org
----- Original Message -----
From: "Dale Strickland-Clark" <da...@riverhall.NOSPAMco.uk>


> I observe that the folowing works as some might expect:
>
> x = y = 5
>
> Assigns 5 to both x and y.
>
> However the expression:
>
> y = 5
>
> does not yeild 5
>
> >>> print y = 5
> Traceback ( File "<interactive input>", line 1
> print y = 5
> ^
> SyntaxError: invalid syntax
> >>>
>
> So this is obviously a gludge in assignment.
>
> I'd be much happier if assignment yeilds the value assigned, as it
> does in C (I believe). It could then be used universaly.

Assignment isn't an expression, it's a statement. What you are requesting
is asked for all the time; Guido decided against it a long time ago because
constructions like:

if c = 1:
...

are almost certainly not what the programmer had in mind. C does the
wrong thing; Python throws an error so the programmer can see what he or
she did wrong immediately.

> Also, where is this curious behaviour documented? 6.3 of the Language
> Ref makes no reference to it. (Go on. Prove me wrong!)

The simple fact that it's in section 6 (Statements) instead of 5
(Expressions)
gives the answer.

> Thanks.
> --
> Dale Strickland-Clark
> Riverhall Systems Ltd

> --
> http://mail.python.org/mailman/listinfo/python-list
>
>


Martin von Loewis

unread,
Oct 8, 2001, 9:04:13 AM10/8/01
to
Dale Strickland-Clark <da...@riverhall.NOSPAMco.uk> writes:

> I'd be much happier if assignment yeilds the value assigned, as it
> does in C (I believe). It could then be used universaly.
>
> Also, where is this curious behaviour documented? 6.3 of the Language
> Ref makes no reference to it. (Go on. Prove me wrong!)

Since you're asking for it:

6.3 clearly states that

x = y = 5 # (1)

is legal syntax; the

(target_list "=")+

portion matches twice, with the first 'target_list' being 'x', and the
second 'target_list' being 'y'.

It then also explains you what this statement does:

"An assignment statement evaluates the expression list (...) and
assigns the single resulting object to each of the target lists, from
left to right."

So it evaluates the expression first, which gives the value 5,
then assignes it first to x, then to y.

Now, you where asking why

print y = 5 # (2)

is not allowed. This can be answered by looking at the 6.6,

print_stmt: "print" [ expression ("," expression)* [","] ]

For this statement to be valid, 'y = 5' needs to be an expression.
Looking at 5.10, you'll notice that 'expression' will not allow for
'y = 5', so the code (2) is clearly ill-formed.

In short, assignment is not an expression in Python; that's why it is
listed in statements (section 6), not in expressions (section 5).

You can wish that assignment was an expression. But there are many
good reasons why it shouldn't, backwards-compatibility and less
confusion being among them. On the "less confusion" part: The C
pitfall

if(x=0)

is enough reason alone not to have assignment as an expression in a
language. The only reason to make assignment an expression in C was to
allow

x = y = 5

but Python achieves this through different means.

Regards,
Martin

Dale Strickland-Clark

unread,
Oct 8, 2001, 9:58:54 AM10/8/01
to
Thanks everyone.

"assignment_stmt: (target_list "=")+ expression_list"

That little '+' escaped me.

I accept the confusion that the examples make possible:

if(x=0)

are not desirable.

So how about an alternative assignment operator that can't be confused
with equality but which yeilds the assigned value?

Pascal uses :=
Another language (I forget which) uses <-

(I've always prefered := for assignment and a plain = for equality.)

I don't suppose I'm the first to suggest this, either.

Richard Brodie

unread,
Oct 8, 2001, 10:58:22 AM10/8/01
to

"Dale Strickland-Clark" <da...@riverhall.NOSPAMco.uk> wrote in message
news:8tb3stc5jcqfc0mh8...@4ax.com...

> So how about an alternative assignment operator that can't be confused
> with equality but which yeilds the assigned value?
>
> Pascal uses :=

Nope. Pascal is like Python, it doesn't have an assignment operator.


John Roth

unread,
Oct 8, 2001, 11:28:21 AM10/8/01
to

"Richard Brodie" <R.Br...@rl.ac.uk> wrote in message
news:9pseug$j...@newton.cc.rl.ac.uk...

But it does have a *syntax* that means assignment, just like Python.
I believe that is what the poster had in mind.

There are a few cases where I would like to do an assignment in the
middle of an expression; the much abused lambda function comes to
mind immediately.

I kind of like ":=".

John Roth
>
>


Richard Brodie

unread,
Oct 8, 2001, 12:29:46 PM10/8/01
to

"John Roth" <john...@ameritech.net> wrote in message news:ts3hb2p...@news.supernews.com...

> > > Pascal uses :=
> >
> > Nope. Pascal is like Python, it doesn't have an assignment operator.
>
> But it does have a *syntax* that means assignment, just like Python.
> I believe that is what the poster had in mind.

It's probably true that the use of := for assignment and = for equality is
less prone to error for those unused to C-like languages. I think it's a
lost battle though unless we want another controversial language change
in Python 3 ;)

In Pascal, code with =/:= confusion won't compile. Unfortunately, I
suspect that is much more significant than the symbols themselves.


Tim Peters

unread,
Oct 8, 2001, 2:26:59 PM10/8/01
to pytho...@python.org
[Dale Strickland-Clark]
> ...

> So how about an alternative assignment operator that can't be confused
> with equality but which yeilds the assigned value?
>
> Pascal uses :=

But doesn't allow it in expressions -- assignment in Pascal is also a
statement.

> Another language (I forget which) uses <-
>
> (I've always prefered := for assignment and a plain = for equality.)
>
> I don't suppose I'm the first to suggest this, either.

Bingo: it's been suggested countless times over the last decade, but before
the introduction of PEPs there's no coherent historical record. Searching a
comprehensive archive is the only tool. Guido's first public word on the
topic appears to be msg #54 (of 161,909 in the egroups/Yahoo archive):

http://groups.yahoo.com/group/python-list/message/54

I agree, reluctantly (because of all the lines of library and
example code I will have to change), that this change should be made;
but it won't be in 0.9.4 if I release that soon. Note that this
still won't give you assignments in expressions as side effects; I
am against such a feature even though it occasionally saves a line of
code -- one of Python's strong points is that it is usually very easy
(and pretty!) to read, and I feel that assignments in expressions
would have a strong negative effect on readability (and prettiness!).

The change he was talking about (affecting "all the lines of library and
example code I will have to change" -- probably amounted to a few hundred at
the time <wink>) was introducing "==" to mean equality in Python. At the
start, "=" meant both equality-testing and assignment. A consequence was
that, and especially in interactive mode,

>>> a = b

was ambiguous. So that didn't last.

In later years, an informal proposal to add ":=" for embedded assignment
made significant progress, but floundered over a combination of ugliness and
lack of consensus. The most popular variant had ":=" binding tightly, so
that e.g.

while myvar := func() != 0:

assigned myvar to func's return value, not to the Boolean outcome. But then

if distance_sq := x**2 + y**2 < 1:

bound distance_sq to x**2, not to the sum. Etc. For every hack to the
precedence rules someone suggested, someone else came up with a natural
example where it was plain surprising. IIRC, this line ended when it was
more-than-less agreed that any use of ":=" would *require* surrounding
parentheses. But that made it even uglier, and proponents got rarer while
the opposition enjoyed a major resurgence in the polls <wink>.

so-its-prospects-look-dim-even-if-it-had-a-pep-ly y'rs - tim


Martin von Loewis

unread,
Oct 8, 2001, 8:20:00 PM10/8/01
to
"Tim Peters" <tim...@home.com> writes:

> But that made it even uglier, and proponents got rarer while
> the opposition enjoyed a major resurgence in the polls <wink>.

Sounds like the report of an observing bystander :-)

Martin

Dale Strickland-Clark

unread,
Oct 9, 2001, 5:01:29 AM10/9/01
to
Thanks for bringing me up-to-date with this debate.

I'm not sure I sympathise with the philosophy that if you can't please
everyone then don't please anyone. An argumentative group can thus
bring progress to a stand-still.

For just about any operator you can come up with an example that needs
parenthesise to behave in the 'natural' way rather than the way forced
by precedence.

Assignment in expressions, particularly in conditional statements can
reduce complexity and simplify legibility.

You can always write code that's difficult to understand and I would
argue that the recently added list comprehension syntax can be a real
pig to decypher but I wouldn't be without it now.

Not introducing a feature because it might make some code more
difficult to understand is on a par with not letting adults buy knives
in case they cut themselves.

That's my twopence worth, anyway. :-)

Martin von Loewis

unread,
Oct 9, 2001, 9:13:17 AM10/9/01
to
Dale Strickland-Clark <da...@riverhall.NOSPAMco.uk> writes:

> I'm not sure I sympathise with the philosophy that if you can't please
> everyone then don't please anyone. An argumentative group can thus
> bring progress to a stand-still.

I don't sympathise with that philosophy, either. However, I cannot see
an instance of it here. I'm quite pleased with the status quo, and I
don't see any problem to solve here.

> That's my twopence worth, anyway. :-)

It may not be worth much more than that... If you seriously want this
feature, you need to write a PEP, and perhaps implement the feature,
gaining user support, etc. Otherwise, I can promise you that nothing
will change.

Regards,
Martin

John Roth

unread,
Oct 9, 2001, 11:35:44 AM10/9/01
to

"Richard Brodie" <R.Br...@rl.ac.uk> wrote in message
news:9psk9s$r...@newton.cc.rl.ac.uk...

>
> "John Roth" <john...@ameritech.net> wrote in message
news:ts3hb2p...@news.supernews.com...
>
> > > > Pascal uses :=
> > >
> > > Nope. Pascal is like Python, it doesn't have an assignment operator.
> >
> > But it does have a *syntax* that means assignment, just like Python.
> > I believe that is what the poster had in mind.
>
> It's probably true that the use of := for assignment and = for equality is
> less prone to error for those unused to C-like languages. I think it's a
> lost battle though unless we want another controversial language change
> in Python 3 ;)

It would be controversial only if we wanted to change the statement
assignment operator. That's not going to happen; I would be against it
in any case since = is pretty much the standard, and has been since
Fortran. Pascal (and I belive Algol) is out of the mainstream on this issue.

However, I think := makes a good choice for an expression assignment
operator. It needs to be different from both the statement assignment
operator and the equality operator. It also can't be in use for an
extended assignment.

Any controversy would be over whether we actually should add this
functionality to Python. I could argue that both ways.

John Roth

Paul Rubin

unread,
Oct 9, 2001, 11:46:51 AM10/9/01
to
"John Roth" <john...@ameritech.net> writes:
> However, I think := makes a good choice for an expression assignment
> operator. It needs to be different from both the statement assignment
> operator and the equality operator. It also can't be in use for an
> extended assignment.

Why on earth does it have to be different from the statement assignment
operator? What's wrong with

while x=get_next(): whatever(x)

I just don't buy the rationale that using = instead of == is a big source
of bugs. In 25 years of hacking C code, I think I've seen that error
maybe once or twice.

Tim Peters

unread,
Oct 10, 2001, 1:25:29 AM10/10/01
to pytho...@python.org
[Dale Strickland-Clark]

> Thanks for bringing me up-to-date with this debate.
>
> I'm not sure I sympathise with the philosophy that if you can't please
> everyone then don't please anyone. An argumentative group can thus
> bring progress to a stand-still.

Take the hint and follow the link I provided: if you don't study the
debates for yourself, you're going to reduce them to shallow
characterizations (like, say, that one) based on imagination. If Guido has
a reputation for anything, fear of not pleasing everyone ain't it.

> For just about any operator you can come up with an example that needs
> parenthesise to behave in the 'natural' way rather than the way forced
> by precedence.

Sure. It's a bad sign when examples aren't strained or contrived, though.

> Assignment in expressions, particularly in conditional statements can
> reduce complexity and simplify legibility.

While a stiff dose of poison can be good for some illnesses -- absolutes
aren't particularly illuminating.

> You can always write code that's difficult to understand and I would
> argue that the recently added list comprehension syntax can be a real
> pig to decypher but I wouldn't be without it now.

Sure and sure, but "difficult to understand" wasn't the issue so much as
"surprising in ordinary cases" and even "not helpful enough often enough to
be worth the costs".

> Not introducing a feature because it might make some code more
> difficult to understand is on a par with not letting adults buy knives
> in case they cut themselves.

It was more akin to not letting adults piss on the toaster because it might
short out and cause a fire <wink>.

opposing-arguments-that-were-actually-made-would-probably-be-more-
interesting-ly y'rs - tim


Tim Peters

unread,
Oct 10, 2001, 1:11:27 AM10/10/01
to pytho...@python.org
[Tim]

> But that made it even uglier, and proponents got rarer while
> the opposition enjoyed a major resurgence in the polls <wink>.

[Martin von Loewis]


> Sounds like the report of an observing bystander :-)

It does, doesn't it? One of my special skills. Still, given the number of
times this debate has occurred over the years, I've actually taken part in
few of them. In the rest, I argued both sides just to keep a finely honed
sense of outrage intact <wink>.

it's-not-a-trivial-language-issue-it's-a-matter-of-moral-urgence-ly
y'rs - tim


Tim Peters

unread,
Oct 10, 2001, 1:49:02 AM10/10/01
to pytho...@python.org
[Paul Rubin, on an expression assignment operator]

> Why on earth does it have to be different from the statement assignment
> operator? What's wrong with
>
> while x=get_next(): whatever(x)
>
> I just don't buy the rationale that using = instead of == is a big source
> of bugs. In 25 years of hacking C code, I think I've seen that error
> maybe once or twice.

I suggest you're highly atypical here, Paul. This was the very first of the
gotchas listed in Andrew Koenig's classic (late 80s) "C Traps and Pitfalls",
and has made nearly every list of C "deadly sins" I've seen since then.
I've wasted weeks of my own life helping people track this error down in C,
too often under extreme time or customer pressure. The experience of the
other folks at PythonLabs is similar, so even if it's a disease you're
immune to, you can be sure this will never go in.

At my last employer, we had a miserable bug that went away in a debug build,
and analysis all but assured that *if* the only plausible cause were
actually occurring, a particular assert would have triggered in the debug
build. But the assert didn't trigger, and a run under the debugger
confirmed the vrbl had its asserted value, so people looked elsewhere.
Oops! The assert turned out to be the perversely self-fulfilling:

assert(i = 1);

and multiple senior programmers with with many decades of industrial C
experience had stared at that multiple times without realizing the mistake.
A complicating factor was that the compiler complained about a raw "(i = 1)"
in control-structure contexts, so perhaps people were lulled into a false
security about this trap.

It only takes one of those to sour you on the idea for life.

dozens-to-spare-ly y'rs - tim


Paul Rubin

unread,
Oct 10, 2001, 3:29:19 AM10/10/01
to
"Tim Peters" <tim...@home.com> writes:

> [Paul Rubin, on an expression assignment operator]
> > Why on earth does it have to be different from the statement assignment
> > operator? What's wrong with
> >
> > while x=get_next(): whatever(x)
> >
> > I just don't buy the rationale that using = instead of == is a big source
> > of bugs. In 25 years of hacking C code, I think I've seen that error
> > maybe once or twice.
>
> I suggest you're highly atypical here, Paul. This was the very first of the
> gotchas listed in Andrew Koenig's classic (late 80s) "C Traps and Pitfalls",
> and has made nearly every list of C "deadly sins" I've seen since then.
> I've wasted weeks of my own life helping people track this error down in C,
> too often under extreme time or customer pressure. The experience of the
> other folks at PythonLabs is similar, so even if it's a disease you're
> immune to, you can be sure this will never go in.

The thing is, it's just not a matter of MY immunities. I've spent
plenty of time debugging other people's code too, and have encountered
all kinds of errors in both their code and mine. The =/== mistake has
just been very rare in my experience. Can it be that the Unix
compilers I use flag the error a lot of the time, so it gets fixed
quickly, while Windows compilers don't flag it, and you're mostly
using Windows compilers?

Anyway, I can live with "while x:=get_next()" instead of x=get_next.
But I feel seriously cramped in Python when I have to say

while 1:
x=get_next()
if not x: break
whatever(x)

so I hope something is done about the issue.

> Oops! The assert turned out to be the perversely self-fulfilling:
>
> assert(i = 1);

Ouch!!!! ;-)

Just van Rossum

unread,
Oct 10, 2001, 3:47:11 AM10/10/01
to
Paul Rubin wrote:

> Anyway, I can live with "while x:=get_next()" instead of x=get_next.
> But I feel seriously cramped in Python when I have to say
>
> while 1:
> x=get_next()
> if not x: break
> whatever(x)
>
> so I hope something is done about the issue.

I think this is the wrong example, as it can easily be written as a
for loop. Iterators in 2.2 will make that even more natural. Now if
you meant this:

m = someRegex.match(...)
if m:
...

vs.

if m := someRegex.match(...):
...

you may have a point...

Just

Andrew Dalke

unread,
Oct 10, 2001, 4:48:13 AM10/10/01
to
Paul Rubin:

>The thing is, it's just not a matter of MY immunities. I've spent
>plenty of time debugging other people's code too, and have encountered
>all kinds of errors in both their code and mine. The =/== mistake has
>just been very rare in my experience. Can it be that the Unix
>compilers I use flag the error a lot of the time, so it gets fixed
>quickly, while Windows compilers don't flag it, and you're mostly
>using Windows compilers?

You're kidding us, aren't you? Or maybe you've only been programming
for the last few years. When I started with unix (IRIX 3.3 in 1990)
it came with a K&R C compiler. It didn't have any of this sort of
checking. That's why 'lint' was written.

And you're saying you've never seen all the code that uses
if (22 == a)
instead of
if (a == 22)
just in case the '==' is accidently replaced with '='? That's
common enough to be mentioned as a joke in Q5.A. of
http://www.ddj.com/columns/stob/2001/0110vs001.htm
] When comparing variables with constants, write the constant
] first to avoid accidental assignment ie write

GCC was the first unix compiler I saw which generated a warning
for this problem. That was about 4 or 5 years ago. But trying
some compilers I have access to (some old C compilers too :)

> uname -a
SunOS day 5.7 Generic sun4d sparc SUNW,SPARCserver-1000
> cc -V
ucbcc: SC3.0.1 13 Jul 1994
...told you it was old :)
>
> cat > test.c
main() {
int i = 0;
if (i = 1) {
printf("Hello.\n");
}
}
> cc test.c
> ./a.out
Hello.
>

With "WorkShop Compilers 5.0 98/12/15 C 5.0" on "SunOS 5.7"
there is no warning.

With "MIPSpro Compilers: Version 7.2.1" on IRIX 6.4 there
*is* a warning.

Don't currently have ready access to other compilers.

Andrew
da...@dalkescientific.com

Paul Wright

unread,
Oct 10, 2001, 6:14:12 AM10/10/01
to
In article <mailman.1002693010...@python.org>,

Tim Peters <tim...@home.com> wrote:
>[Paul Rubin, on an expression assignment operator]
>> Why on earth does it have to be different from the statement assignment
>> operator? What's wrong with
>>
>> while x=get_next(): whatever(x)
>>
>> I just don't buy the rationale that using = instead of == is a big source
>> of bugs. In 25 years of hacking C code, I think I've seen that error
>> maybe once or twice.
>
>I suggest you're highly atypical here, Paul. This was the very first of the
>gotchas listed in Andrew Koenig's classic (late 80s) "C Traps and Pitfalls",
>and has made nearly every list of C "deadly sins" I've seen since then.
>I've wasted weeks of my own life helping people track this error down in C,
>too often under extreme time or customer pressure. The experience of the
>other folks at PythonLabs is similar, so even if it's a disease you're
>immune to, you can be sure this will never go in.

If you're after some quantitative data, Les Hatton[0] lists faults where
"control expression is an assignment" as occurring in 1:3306 lines of C
code in his test population. The practice of doing assignment in
control expressions is banned in safer subsets of C [1].

While I agree it can be annoying to have to write an extra line
occasionally, I think that the benefits outweigh the costs.

[0] Hatton, L, "Safer C: Developing Software for High-integrity and
Safety-critical systems", McGraw-Hill 1994.

[1] eg. The Motor Industry Software Reliability Association's C
Guidelines, http://www.misra.org.uk/

--
----- Paul Wright ------| "Their little anoraks bobbed and danced, their
-paul....@pobox.com--| cycling helmets swung with gay abandon - the NatSci
http://pobox.com/~pw201 | Elves were abroad!" -Simon Pick

John W. Baxter

unread,
Oct 10, 2001, 10:49:55 AM10/10/01
to
In article <mailman.1002693010...@python.org>, Tim
Peters <tim...@home.com> wrote:

> It only takes one of those to sour you on the idea for life.

In my case, that event was receiving some C code from a former boss. He
had looked at the assembly output from a problem area of code and was
wondering why the (early C compiler for Intel 8080) was storing a 0
into memory and then immediately reading the value out and checking
whether it was 0*. Indeed, I spotted
if (a = 0) ...

It wasn't long before I started--along with many others--turning
examples with a literal constant around, producing the uglier but safer
if (0 == a) ...
sort of thing.

I don't want to see Python go down this road.

* Can't trust that darn RAM!...which was somewhat true in the late
1970s.

--John

John Roth

unread,
Oct 10, 2001, 11:25:01 AM10/10/01
to

"Paul Rubin" <phr-n...@nightsong.com> wrote in message
news:7x669o7...@ruckus.brouhaha.com...

You're obviously a much more meticulous programmer than I am,
or than most of the programmers I work with are. That's to your
credit.

However, I've seen that bug many times in lots less code. That may
say something about the lack of quality assurance in the areas I work
in, and you'd be right.

For the rest of the commentary, see Tim Peters' note on another branch
of this thread. I agree completely with the error causing potential of
having the same symbol for assignment and comparison; that's been
noted as early as the Algol 60 compiler, which used := for assignment,
and = for comparison.

A large part of the target audience for languages like Python are not
professional programmers, in the sense that they do programming on a
daily basis. They are professional system administrators, or professionals
in other fields, and do programming as only part of their job or
avocation. A language that makes it difficult to make the more obvious
mistakes, and that doesn't get in the way if you really want to do something
that may turn out to be a real mistake, is ideal for them.

John Roth


John Roth

unread,
Oct 10, 2001, 11:30:23 AM10/10/01
to

"Andrew Dalke" <da...@dalkescientific.com> wrote in message
news:9q121p$aia$1...@slb0.atl.mindspring.net...

I believe that the AIX compiler I used on an IBM SP had that
warning. However, it was burried in so many other warnings and
non-sensical comments that most of us had it turned off. I did a
Perl script (this was before I knew about Python) to filter the
warnings to just those I had to deal with. It helped reliability
immensely.

John Roth
>
> Andrew
> da...@dalkescientific.com
>
>
>


James_...@i2.com

unread,
Oct 10, 2001, 2:00:05 PM10/10/01
to pytho...@python.org

Tim Peters wrote:
<snip>

Oops! The assert turned out to be the perversely self-fulfilling:

assert(i = 1);

and multiple senior programmers with many decades of industrial C


experience had stared at that multiple times without realizing the mistake.

<snip>

I could certainly look at that a bunch of times and think "equality"
instead of "assignment". This is one of the reasons why Smalltalk (among
other languages) insisted on *not* using "=" to spell assignment. In my
experience, when assignment is *not* spelled with "=" such mistakes don't
come up in practice. And then it *is* acceptable (and very convenient) to
make assignment an expression.

Jim

David Bolen

unread,
Oct 10, 2001, 3:14:19 PM10/10/01
to
"Tim Peters" <tim...@home.com> writes:

> [Paul Rubin, on an expression assignment operator]
> > Why on earth does it have to be different from the statement assignment
> > operator? What's wrong with
> >
> > while x=get_next(): whatever(x)
> >
> > I just don't buy the rationale that using = instead of == is a big source
> > of bugs. In 25 years of hacking C code, I think I've seen that error
> > maybe once or twice.
>
> I suggest you're highly atypical here, Paul. This was the very first of the
> gotchas listed in Andrew Koenig's classic (late 80s) "C Traps and Pitfalls",
> and has made nearly every list of C "deadly sins" I've seen since then.
> I've wasted weeks of my own life helping people track this error down in C,
> too often under extreme time or customer pressure. The experience of the
> other folks at PythonLabs is similar, so even if it's a disease you're
> immune to, you can be sure this will never go in.

I've got to admit to being a big fan/user of assignment as an
expression in my C code, so I also miss it in Python at times. But on
the whole I think Python probably made the right choice, at least
while "=" and "==" are the tokens in question.

I know I've myself created this bug a lot more than once or twice in C
code in my past 17 years or so, and have also seen it in many others
code. Within my own code, the big difference over time has been being
quicker to notice since I was aware of it, so it rarely did much
damage outside of a debug run. But when first trying to diagnose
foreign code it could take quite a while to isolate and waste a lot of
time.

> (...)


> Oops! The assert turned out to be the perversely self-fulfilling:
>
> assert(i = 1);
>
> and multiple senior programmers with with many decades of industrial C
> experience had stared at that multiple times without realizing the mistake.

Yeah, it's almost wierd how easy it is to stare at an expression like
this and simply not notice the problem.

> It only takes one of those to sour you on the idea for life.

Yeah, it's one of those points where being burned once can hurt more
and waste more time than having the functionality available will help
or save time even over a very long time.

--
-- David
--
/-----------------------------------------------------------------------\
\ David Bolen \ E-mail: db...@fitlinxx.com /
| FitLinxx, Inc. \ Phone: (203) 708-5192 |
/ 860 Canal Street, Stamford, CT 06902 \ Fax: (203) 316-5150 \
\-----------------------------------------------------------------------/

John Roth

unread,
Oct 10, 2001, 5:54:29 PM10/10/01
to

<James_...@i2.com> wrote in message
news:mailman.1002736876...@python.org...

Which was exactly my point in another branch of this discussion.
It's also been pointed out that "=" is not a good symbol for assignment -
it's just the one that Fortran chose to use, and its the reason that
Algol chose ":=" as the assignment operator, with Pascal following
in that path.

In mathematics, "=" is an assertion that two expressions have the same
value over the applicable portion of the domain. Pure mathematics
doesn't have an equivalent of assignment.

However, this is a lost arguement in terms of an existing language.
Transitioning assignment to some other symbol would be a huge pain
for not very much (percieved) gain.

John Roth
>
>
>


Huaiyu Zhu

unread,
Oct 10, 2001, 6:00:13 PM10/10/01
to
I have an alternative syntax that could satisfy both safety and simplicity.
It did not receive much notice the last time here, though. The full
explanation is at http://www.geocities.com/huaiyu_zhu/python/ififif.txt

On Wed, 10 Oct 2001 09:47:11 +0200, Just van Rossum <ju...@letterror.com> wrote:
>Paul Rubin wrote:
>
>> Anyway, I can live with "while x:=get_next()" instead of x=get_next.
>> But I feel seriously cramped in Python when I have to say
>>
>> while 1:
>> x=get_next()
>> if not x: break
>> whatever(x)
>>
>> so I hope something is done about the issue.

while x = get_next(); x:
whatever(x)

>
>I think this is the wrong example, as it can easily be written as a
>for loop. Iterators in 2.2 will make that even more natural. Now if
>you meant this:
>
> m = someRegex.match(...)
> if m:
> ...
>
>vs.
>
> if m := someRegex.match(...):
> ...
>
>you may have a point...
>
>Just

if m = someRegex.match(...); m:
...

There are several other uses for this syntax. For example,

if val = dict1[key1]; val:
process1(val)
elif val = dict2[key2]; val:
process2(val)
elif mylist += otherlist; len(mylist) > 4:
process3(mylist)
...

These are arguably easier to understand than current Python syntax.
See the link above for more examples.

Is there much interest to turn this into a PEP?

Huaiyu

Greg Ewing

unread,
Oct 10, 2001, 8:21:57 PM10/10/01
to
Paul Rubin wrote:
>
> I feel seriously cramped in Python when I have to say
>
> while 1:
> x=get_next()
> if not x: break
> whatever(x)

I feel the solution to this is *not* to go in for
any sort of assignment-in-expressions hackery, but
to provide a decent loop-and-a-half control structure.
My current idea for this is

while:
x = get_next()
gives x:
whatever(x)

--
Greg Ewing, Computer Science Dept, University of Canterbury,
Christchurch, New Zealand
To get my email address, please visit my web page:
http://www.cosc.canterbury.ac.nz/~greg

John W. Baxter

unread,
Oct 11, 2001, 12:40:29 AM10/11/01
to
In article <ts9gn1b...@news.supernews.com>, John Roth
<john...@ameritech.net> wrote:

> and its the reason that
> Algol chose ":=" as the assignment operator, with Pascal following
> in that path.

Which I prefer, even though:

I never used a keyboard on which : and = used the same state of the
shift key. (I used a few which were the reverse of what we--on US
keyboards--now expect, with : unshifted and = shifted.)

Thus (on current US keyboards), one sees occasional ;= and :+ (which
fortunately aren't symbols of many languages and generally lead to
syntax errors).

--John

Chris Dutton

unread,
Oct 11, 2001, 2:46:43 AM10/11/01
to
in article slrn9s9h7p...@gauss.almadan.ibm.com, Huaiyu Zhu at
hua...@gauss.almadan.ibm.com wrote on 10/10/01 6:00 PM:

> There are several other uses for this syntax. For example,
>
> if val = dict1[key1]; val:
> process1(val)
> elif val = dict2[key2]; val:
> process2(val)
> elif mylist += otherlist; len(mylist) > 4:
> process3(mylist)

The example I saw somewhere that I liked was

if something as x:
do_something_to(x)

Paul Rubin

unread,
Oct 11, 2001, 4:11:44 AM10/11/01
to
Chris Dutton <ch...@cmb-enterprises.com> writes:
> > There are several other uses for this syntax. For example,
> >
> > if val = dict1[key1]; val:
> > process1(val)
> > elif val = dict2[key2]; val:
> > process2(val)
> > elif mylist += otherlist; len(mylist) > 4:
> > process3(mylist)

Hey, I like that, especially if you can use that PROG-like structure
in ordinary expressions, similar to the comma operator in C.

> The example I saw somewhere that I liked was
>
> if something as x:
> do_something_to(x)

That's ok too, as long as the comparison doesn't have to be with zero:
if (something as x) == 3:
do_something_to(x)

Dale Strickland-Clark

unread,
Oct 11, 2001, 5:46:53 AM10/11/01
to
Greg Ewing <gr...@cosc.canterbury.ac.nz> wrote:

>I feel the solution to this is *not* to go in for
>any sort of assignment-in-expressions hackery, but
>to provide a decent loop-and-a-half control structure.
>My current idea for this is
>
> while:
> x = get_next()
> gives x:
> whatever(x)

I think I see what you're getting at but it doesn't really do it for
me.

The general loop construct as found in C and Java where you have three
expressions: initialisation, increment/iteration, test is a very
flexible and powerful approach which I really like.

Dale Strickland-Clark

unread,
Oct 11, 2001, 5:55:41 AM10/11/01
to
Chris Dutton <ch...@cmb-enterprises.com> wrote:

Presumably, 'something as x' assigns to x and yields x?

It doesn't seem at all obvious to me. I had to think about it for a
while before figuring it out. Also, having an assignment working to
the right is very counter-intuitive.

Boyd Roberts

unread,
Oct 11, 2001, 5:00:54 AM10/11/01
to pytho...@python.org
"John W. Baxter" wrote:
>
> I never used a keyboard on which : and = used the same state of the
> shift key.

I'm typing on one right now:

<shift> : =

Nice for limbo.

Markus Schaber

unread,
Oct 11, 2001, 11:31:24 AM10/11/01
to
Hi,

John W. Baxter <jwba...@spamcop.net> schrub:

> I never used a keyboard on which : and = used the same state of the
> shift key. (I used a few which were the reverse of what we--on US
> keyboards--now expect, with : unshifted and = shifted.)

Just use German keyboard Layout. : is shift-. and = is shift-0

But there's a drawback: Trying to type :-) means Shift-:, then (without
shift) a -, and after that shift-9... :-)

markus
--
You don't have to be Microsoft to suck... but it helps.
(Tim Hammerquist in comp.lang.python)

Donn Cave

unread,
Oct 11, 2001, 12:55:05 PM10/11/01
to
Quoth Dale Strickland-Clark <da...@riverhall.NOSPAMco.uk>:
...

| The general loop construct as found in C and Java where you have three
| expressions: initialisation, increment/iteration, test is a very
| flexible and powerful approach which I really like.

I sort of regret wasting bandwidth on this purely academic question,
but it's a matter of truly venerable tradition that C's loop is a
bit shy of perfection. The idea as I understand it, is that there
are essentially two control points in a loop, the entry, and the
conditional repeat. C conflates those two in one, because both
entry and the conditional repeat have to be at the "top".

There are plenty of applications for a separate entry, and that's
where we came in. The most frequently cited application for an
assignment expression is

while line = file.readline():
...

A very flexible and powerful approach to looping would allow you
to enter the loop in time to set up for the condition, however many
statements that might take. C and Python give you one expression,
and in C that expression can be an assignment. If you can't do what
you need there, then you have to choose between A) repeat the same
code before the loop:

line = file.readline()
while line:
...
line = file.readline()

or B) take the condition out of the loop control (standard Python solution)

while 1:
line = file.readline()
if not line:
break

People who claim that C fixes this just expose the limitations of
their thinking. C does not fix this, by allowing an assignment
there, except in the restricted case where the pre-conditional
part of the loop can fit into one expression. (Note that I'm not
talking about the initialization section of for(), which is a
pure non-feature - those statements can just as well be written
before the loop.)

Anyone writing a new language should obviously think about that (if
the language has any looping constructs at all - there are so many
"functional" languages crowding the landscape that I'm not sure anyone
invents procedural languages these days.)

Donn Cave, do...@u.washington.edu

Dale Strickland-Clark

unread,
Oct 11, 2001, 2:17:09 PM10/11/01
to
Donn Cave <do...@u.washington.edu> wrote:

>I sort of regret wasting bandwidth on this purely academic question,
>but it's a matter of truly venerable tradition that C's loop is a
>bit shy of perfection. The idea as I understand it, is that there
>are essentially two control points in a loop, the entry, and the
>conditional repeat. C conflates those two in one, because both
>entry and the conditional repeat have to be at the "top".

I didn't suggest it was perfect, just that I liked it.

<snip>

>People who claim that C fixes this just expose the limitations of
>their thinking. C does not fix this, by allowing an assignment
>there, except in the restricted case where the pre-conditional
>part of the loop can fit into one expression. (Note that I'm not
>talking about the initialization section of for(), which is a
>pure non-feature - those statements can just as well be written
>before the loop.)

Not so. It can avoid an extra enclosing block in cases such as:

if (x==y)
for (initialise loop; ....)
do something

Which is less fussy than

if (x==y)
{ initialise loop
for (....)
do something

Mike Ryan

unread,
Oct 11, 2001, 2:29:54 PM10/11/01
to
"Dale Strickland-Clark" <da...@riverhall.NOSPAMco.uk> wrote in message
news:qtqast8mifvlmhpv3...@4ax.com...

> Chris Dutton <ch...@cmb-enterprises.com> wrote:
> >The example I saw somewhere that I liked was
> >
> >if something as x:
> > do_something_to(x)
>
> Presumably, 'something as x' assigns to x and yields x?
>
> It doesn't seem at all obvious to me. I had to think about it for a
> while before figuring it out. Also, having an assignment working to
> the right is very counter-intuitive.

Actually, it's not all that different from the "import ... as ..." syntax
of the statement:

import spam as bacon
dir(bacon)

--

Michael Ryan
Information Services Manager
21st Century Health and Benefits, Inc.

Paul Winkler

unread,
Oct 11, 2001, 3:27:32 PM10/11/01
to
On 11 Oct 2001 16:55:05 GMT, Donn Cave <do...@u.washington.edu> wrote:
>There are plenty of applications for a separate entry, and that's
>where we came in. The most frequently cited application for an
>assignment expression is
>
> while line = file.readline():
> ...

That's not a very compelling example anymore. Presumably you don't
want to do "for line in file.readlines()" because of the memory
implications of slurping the whole file? Well, as of python 2.1 we can
get one line at a time like this:

for line in file.xreadlines():
...

And as of Python 2.2, files have an iterator that lets us do it like this:

for line in file:
...

Of course, we've already had the xreadlines module for quite a while,
but the new sugary way to do it is easier to remember.


- Paul Winkler


John Roth

unread,
Oct 11, 2001, 3:40:41 PM10/11/01
to

"Greg Ewing" <gr...@cosc.canterbury.ac.nz> wrote in message
news:3BC4E625...@cosc.canterbury.ac.nz...

> Paul Rubin wrote:
> >
> > I feel seriously cramped in Python when I have to say
> >
> > while 1:
> > x=get_next()
> > if not x: break
> > whatever(x)
>
> I feel the solution to this is *not* to go in for
> any sort of assignment-in-expressions hackery, but
> to provide a decent loop-and-a-half control structure.
> My current idea for this is
>
> while:
> x = get_next()
> gives x:
> whatever(x)

The notion that while is adequate as a looping construct
comes from the minimalist school. From a techincal
point, they are right, but from a pragmatic point of writing
economical, understandable programs, they are wrong.

If you're going to expand the loop syntax, all four (or five)
parts should be explicit: initialization, test, reinitialization,
body and possibly zero-trip exception. In particular,
test should allow more than one expression: it should allow
either a single expression or any number of statements. In
this case, exit would require an explicit break.

Unfortunately, this gets to be more than a bit cumbersome.

John Roth

Paul Rubin

unread,
Oct 11, 2001, 3:48:28 PM10/11/01
to
slin...@yahoo.com (Paul Winkler) writes:
> That's not a very compelling example anymore. Presumably you don't
> want to do "for line in file.readlines()" because of the memory
> implications of slurping the whole file? Well, as of python 2.1 we can
> get one line at a time like this:
>
> for line in file.xreadlines():
> ...

What if you want to read until you get to a delimiter?

while (line := readline()) != 'end': ...

Tim Peters

unread,
Oct 11, 2001, 3:30:24 PM10/11/01
to pytho...@python.org
[Donn Cave]
> ...

> Anyone writing a new language should obviously think about that (if
> the language has any looping constructs at all - there are so many
> "functional" languages crowding the landscape that I'm not sure anyone
> invents procedural languages these days.)

That's true: Python was the last one. This was confirmed at the last
International Language Design Conference, where a unanimous resolution held
that "Python is it for procedural languages -- we don't need more.".
Guido's brief acceptance speech was a marvel of Pythonic pithiness: "Told
you so.".

OTOH, functional language designers are very much in the business of adding
loop constructs to their languages, because, on the whole, they're very keen
to get a user who isn't a functional language designer <wink>.

reporting-all-the-news-that's-fit-to-believe-ly y'rs - tim


Markus Schaber

unread,
Oct 11, 2001, 4:13:11 PM10/11/01
to
Hi,

Paul Rubin <phr-n...@nightsong.com> schrub:

> Anyway, I can live with "while x:=get_next()" instead of x=get_next.

> But I feel seriously cramped in Python when I have to say


>
> while 1:
> x=get_next()
> if not x: break
> whatever(x)
>

> so I hope something is done about the issue.

Using cutting-edge Python, one might wrap it with an iterator:

def seq():
temp = get_next()
while temp:
yield temp
temp = get_next()

And then easily use it this way:

for i in seq():
whatever(x)

(this code is not tested, as I currently don't have a 2.2 python here.)

Markus Schaber

unread,
Oct 11, 2001, 4:16:11 PM10/11/01
to
Hi,

Donn Cave <do...@u.washington.edu> schrub:

> (Note that I'm not
> talking about the initialization section of for(), which is a
> pure non-feature - those statements can just as well be written
> before the loop.)

There's one difference: You can define temporary variables which
are only valid inside of the for statement.

But this may be emulated creating an artificial {} block around
it.

David Bolen

unread,
Oct 11, 2001, 5:13:07 PM10/11/01
to
Dale Strickland-Clark <da...@riverhall.NOSPAMco.uk> writes:

> Not so. It can avoid an extra enclosing block in cases such as:
>
> if (x==y)
> for (initialise loop; ....)
> do something
>
> Which is less fussy than
>
> if (x==y)
> { initialise loop
> for (....)
> do something
> }

Except that I'd never recommend writing the former (initialization or
not) since you're just asking for maintenance headaches later when
someone tries to add a new statement to the conditional and forgets to
add the block back in.

Alex Martelli

unread,
Oct 11, 2001, 5:33:20 PM10/11/01
to
Paul Rubin wrote:
...

>> for line in file.xreadlines():
>> ...
>
> What if you want to read until you get to a delimiter?
>
> while (line := readline()) != 'end': ...

for line in file.xreadlines():
if line == 'end': break
etcetc(line)

Of course, if you're transliterating from some other language and need to
keep close structure similarity (e.g. for didactic reasons), Python makes
that easy too, see e.g. the rather obvious approach of my recipe:

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66061

which would give:

while data.set(file.readline()) != 'end':
process(data.get())


Alex

Huaiyu Zhu

unread,
Oct 11, 2001, 5:58:35 PM10/11/01
to
On Thu, 11 Oct 2001 13:21:57 +1300, Greg Ewing <gr...@cosc.canterbury.ac.nz>
wrote:

>I feel the solution to this is *not* to go in for
>any sort of assignment-in-expressions hackery, but
>to provide a decent loop-and-a-half control structure.

A general "loop-and-half" structure is

A
start loop
B
if C: break
D
end loop
E

Which could be written in the following pattern

A
while B; C:
D
E

Example 1:

> while:
> x = get_next()
> gives x:
> whatever(x)

could be written as

while x = get_next(); x:
whatever(x)

Example 2:

> What if you want to read until you get to a delimiter?
>
> while (line := readline()) != 'end': ...

could be written as

while line = readline(); line != 'end': ...

Example 3:

for (start; do_other, end; incr) do_something;

could be written as

start
while do_other; not end:
do_something
incr

Likewise, a general nested "if-else-and-a-half" structure is like

A
if B:
C
else:
D
if E:
F
else:
G
if H:
I
else:
...

which could be written as

if A; B:
C
elif D; E:
F
elif G; H:
I
else:
...

The advantage of this syntax pattern is that it is flatter than existing
Python syntax, which is a Good Thing <tm>. The disadvantage is that it
cannot handle additional statement after nested 'else', but the existing
'elif' pattern could not do it, either.


Huaiyu

Greg Ewing

unread,
Oct 11, 2001, 8:52:08 PM10/11/01
to
Markus Schaber wrote:
>
> But there's a drawback: Trying to type :-) means Shift-:, then (without
> shift) a -, and after that shift-9... :-)

That's not unique to German keyboards -- the same
shift pattern applies to the one I'm using now!

The general solution obviously is to connect two
keyboards to your computer, one permanently shifted
and the other permanently non-shifted.

Quinn Dunkan

unread,
Oct 11, 2001, 11:18:20 PM10/11/01
to

for line in iter(open('file').readline, 'end\n'):
...


In programming you define functions to capture your patterns. I'd rather
write a function than redesign the language. And in this case, the function
is already written (not that I expected you to know that since it's new).

I've never felt the need for loops with more eyebrows. I'd rather define
a higher level abstraction and keep the loop as a simple-as-possible
implementation detail. If we had a nicer syntax for generators we could get
rid of while entirely and have only one looping construct:

def while(p):
if not p: fail()

loop: # loops until top generator fails
while(x == y) # fails if value is false
...

loop:
line = open('foo').readline() # fails when out of lines
if line.startswith('#'): fail() # fails immediately
word = line.split() # fails when out of words
...


Of course this wouldn't be python any more (or even icon). When I write my
own language... :)

Paul Rubin

unread,
Oct 12, 2001, 1:04:57 AM10/12/01
to
qu...@hork.ugcs.caltech.edu (Quinn Dunkan) writes:
> In programming you define functions to capture your patterns. I'd rather
> write a function than redesign the language. And in this case, the function
> is already written (not that I expected you to know that since it's new).

I think it's a mistake to expose too much abstract machinery in
Python, which is supposed to be a practical language. Like you, I
don't see a need for a lot of "eyebrows" in loops, but I feel Python
suffers by ignoring the tried and true.

Just today I had a bug that went something like:

n = compute_number_of_items()
for i in range(n):
try: process_an_item(items[i])
except: break
update_database('number of items processed = ' % i)

The corresponding C code would have been similar except instead
of "for i in range(n)" it would have said "for (i=0; i<n; i++)".

I tested the Python code on some sample data and it worked fine, so I
checked it in. Then a while later it hit some real data where the
number of items was 0. The C-style for loop would have initialized i
to 0 and then executed the loop zero times, clearly the right thing.
The Python for loop does this cutesy-poo set-theoretic thing instead
(even uselessly allocating a potentially huge block of memory unless
you use xrange instead of range), so that if the range is empty, i
never gets initialized and the update_database call throws an
uninitialized variable exception. Anyway it wasn't a big deal
but I think Python would be improved by having a more traditional
loop construct.

Donn Cave

unread,
Oct 12, 2001, 1:53:25 AM10/12/01
to
Quoth Paul Rubin <phr-n...@nightsong.com>:
...

| I think it's a mistake to expose too much abstract machinery in
| Python, which is supposed to be a practical language. Like you, I
| don't see a need for a lot of "eyebrows" in loops, but I feel Python
| suffers by ignoring the tried and true.
|
| Just today I had a bug that went something like:
|
| n = compute_number_of_items()
| for i in range(n):
| try: process_an_item(items[i])
| except: break
| update_database('number of items processed = ' % i)
|
| The corresponding C code would have been similar except instead
| of "for i in range(n)" it would have said "for (i=0; i<n; i++)".
|
| I tested the Python code on some sample data and it worked fine, so I
| checked it in. Then a while later it hit some real data where the
| number of items was 0. The C-style for loop would have initialized i
| to 0 and then executed the loop zero times, clearly the right thing.
| The Python for loop does this cutesy-poo set-theoretic thing instead
| (even uselessly allocating a potentially huge block of memory unless
| you use xrange instead of range), so that if the range is empty, i
| never gets initialized and the update_database call throws an
| uninitialized variable exception. Anyway it wasn't a big deal
| but I think Python would be improved by having a more traditional
| loop construct.

I am not a big fan of the for i in range() idiom, myself. But you
aren't required to use it. If you want the effect of

for (i = 0; i<n; i++) {
--- do stuff --
}

then in Python, you write

i = 0
while i < n:
--- do stuff --
i = i + 1

"wc" says that's 7 more characters to type, which would be a concern
if you have to engrave it on linoleum or something. And you have to
avoid "continue". It seems to me this is the loop construct that people
must use, though, if they're going to expect the tricks they learn
in C to work. Python's "for" loop is really a different thing, not
something I ever found all that cutesy-poo, just a sequence thing
that you see in plenty of languages but not C.

Donn Cave, do...@drizzle.com

Michael Abbott

unread,
Oct 12, 2001, 3:00:56 AM10/12/01
to
Donn Cave <do...@u.washington.edu> wrote in
news:9q4it9$tio$1...@nntp6.u.washington.edu:

> I sort of regret wasting bandwidth on this purely academic question,
> but it's a matter of truly venerable tradition that C's loop is a
> bit shy of perfection. The idea as I understand it, is that there
> are essentially two control points in a loop, the entry, and the
> conditional repeat. C conflates those two in one, because both
> entry and the conditional repeat have to be at the "top".

Perhaps it's worth recalling at this point the syntax used by Algol68 for a
loop. This was really quite pretty and possibly slightly relevant:

WHILE
statements;
expression
DO
statements
OD

Of course, in C this needs to be translated to:

while(1)
{
statements;
if (!expression) break;
statements;
}

and in Python we have to do exactly the same:

while 1:
statements:
if not expression: break
statements

<Shrug> It's not pretty, but I'd rather worry about having a conditional
expression (off topic; we've already beaten that to death and not quite
managed a PEP out of it...)

Michael Hudson

unread,
Oct 12, 2001, 4:51:42 AM10/12/01
to
Donn Cave wrote:


> I am not a big fan of the for i in range() idiom, myself. But you
> aren't required to use it. If you want the effect of
>
> for (i = 0; i<n; i++) {
> --- do stuff --
> }
>
> then in Python, you write
>
> i = 0
> while i < n:
> --- do stuff --
> i = i + 1
>
> "wc" says that's 7 more characters to type, which would be a concern
> if you have to engrave it on linoleum or something. And you have to
> avoid "continue".


i = 0
while i < n:

try:
--- do stuff ---
finally:
i += 1

('prolly only works in relatively recent Pythons)

Anyone using this as an idiom deserves a slap, though.

> It seems to me this is the loop construct that people
> must use, though, if they're going to expect the tricks they learn
> in C to work.


Such people already have major problems, no?

> Python's "for" loop is really a different thing, not
> something I ever found all that cutesy-poo, just a sequence thing
> that you see in plenty of languages but not C.


It is subtly changing in 2.2, of course.


Cheers,
M.

Huaiyu Zhu

unread,
Oct 12, 2001, 3:56:47 PM10/12/01
to
On Thu, 11 Oct 2001 23:33:20 +0200, Alex Martelli <al...@aleax.it> wrote:
[...]
>
>for line in file.xreadlines():
> if line == 'end': break
> etcetc(line)
[...]

>
>while data.set(file.readline()) != 'end':
> process(data.get())
>

Alex, what's your opinion comparing these to the following?

while line = file.xreadlines(); line != 'end':
etcetc(line)


I'm pushing for this because it is not just syntactic suguar. It gives
semantic advantage as well. For example,

while x = next(); not x.is_end:
y = process(x)
if y.is_what_we_are_looking_for(): break
else:
raise "not found"

It is not equivalent to this naive version:

while 1:
x = next()
if x.is_end: break
y = process(x)
if y.is_what_we_are_looking_for(): break
else:
raise "not found"


That's because there are two breaks that have different semantical meanings.
The fully equivalent version in today's syntax has to use one extra variable
(assuming the variable _flag is not used for other purpose):

_flag = 0
while 1:
x = next()
if x.is_end: break
y = process(x)
if y.is_what_we_are_looking_for():
_flag = 1
break
if not _flag:
raise "not found"
del _flag

This is a lot of verbage that does not say directly what we intend to do.


Huaiyu

Ian Parker

unread,
Oct 12, 2001, 6:57:30 PM10/12/01
to
In article <Xns913851934E5D...@194.238.50.13>, Michael
Abbott <mic...@rcp.co.uk> writes


In fact, IIRC, it was prettier and possibly more relevant:

for i by j to k while t do x od

where i,j,m,t,x are expressions (which could be one or more statements),
and the phrases "for i", "by j", "to k", "while t" are optional, with
reasonable defaults.

So you could briefer forms:

for i to k do statements od

or
while t do statements od

or the infinite loop:

do statements od


--
Ian Parker

Michael Chermside

unread,
Oct 12, 2001, 6:08:12 PM10/12/01
to
Michael Abbott writes:
> <Shrug> It's not pretty, but I'd rather worry about having a
> conditional expression (off topic; we've already beaten that to death
> and not quite managed a PEP out of it...)

Actually, that's not QUITE true.

I submitted a proposed PEP not long ago, and got a lot of comments.
Unfortunately, I didn't see any consensus begin to emerge, at least not
one that I could recognize. So I decided I should put it away for a
month or so, then come back with a fresh mind to create the version I
actually submitted. It's my theory (untested, of course) that this will
result in a better initial PEP and thus a better chance of acceptance.

Anyhow, it's almost been that month now, so I ought to get myself
together and get back to this. As before, if anyone else feels strongly
that they'd like to contribute (other than the excellent comments
several folks already made), they should email me.

hoping-that-less-speed-and-more-thinking-leads-to-a-better-design-ly yours,

-- Michael Chermside


Jyrinx

unread,
Oct 12, 2001, 7:02:10 PM10/12/01
to
Erm, I'm hardly a seasoned hacker, but if I may toss in a few cents ...

> | n = compute_number_of_items()
> | for i in range(n):
> | try: process_an_item(items[i])
> | except: break
> | update_database('number of items processed = ' % i)

Paul Rubin pointed out the problem with the empty "items" array (i never
gets initialized, exception is thrown), saying that the C way is more
concise and deals with this. Donn Cave said he doesn't like the "for x in
range()" stuff, would opt for a while loop with manual incrementation.

I like Python's for loop, "range()" idiom and all. In any case, I should
think the above code would be clearer anyway with an explicit check for an
empty list:

n = compute_number_of_items()
if n == 0:
update_database('no items processed')
else:


for i in range(n):
try: process_an_item(items[i])
except: break

update_database('number of items processed = ' % i) # (Hmm? I
thought the % operator was supposed to be used with a string and a
dictionary? Not that # I would know what I'm talking about ... :-)

Or, if you didn't want to make an extra branch and didn't want the
uninitialized-i problem, why not just initialize it to 0 before the loop?

Jyrinx
jyrinx at mindspring dot com

"Donn Cave" <do...@drizzle.com> wrote in message
news:10028660...@yabetcha.drizzle.com...

Jeff Shannon

unread,
Oct 12, 2001, 7:55:04 PM10/12/01
to
>
> That's because there are two breaks that have different semantical meanings.
> The fully equivalent version in today's syntax has to use one extra variable
> (assuming the variable _flag is not used for other purpose):

Nope. (see below)

>
>
> _flag = 0
> while 1:
> x = next()
> if x.is_end: break
> y = process(x)
> if y.is_what_we_are_looking_for():
> _flag = 1
> break
> if not _flag:
> raise "not found"
> del _flag
>

while 1:
x = next()
if x.is_end(): break
y = process(x)
if not y.is_good_result():
raise "not found"

Personally, I think that the construct you are promoting,

while (expression); (condition):
(suite)

.... is ugly and non-intuitive, and I would *not* want to use it. Just my
opinion, but.....


Jeff Shannon
Technician/Programmer
Credit International

Tim Peters

unread,
Oct 12, 2001, 7:01:38 PM10/12/01
to
[Michael Chermside, on a conditional expression]
> ...

> As before, if anyone else feels strongly that they'd like to contribute
> (other than the excellent comments several folks already made), they
> should email me.

If people sign off on taking "then" as a new keyword, I think the chances
are good that we could get

x = if e1 then e2 else e3

into 2.2b1. That's the only obvious spelling, hence the only truly Pythonic
way to spell it. Other languages spelling it that way range from Algol-60
(Guido's first intense language affair) to Haskell.

> hoping-that-less-speed-and-more-thinking-leads-to-a-better-design-
> ly yours,

less-thinking-will-get-there-faster<wink>-ly y'rs - tim


Donn Cave

unread,
Oct 12, 2001, 8:03:17 PM10/12/01
to
Quoth "Jyrinx" <jyrinx at mindspring dot com>:

Good practice for sure, but I think the point may have been that
you shouldn't have to go to so much extra trouble, for safe code.
You pretty much had to anticipate the problem, to think to make
those provisions for it, and if 0 items is an exceptional case,
you'd be very likely to to neglect them. Once this potential occurs
to you, it's very easy to solve that problem.

Here's an idea - suppose the block has its own scope! Now a reference
to "i" is illegal outside the block. More or less like global scope
vs. function local - if i was assigned to prior to the block, then the
binding is inherited by the block, but new names are bound in the block
scope. Not just the for variable, any assignment - after all, the
problem is exactly the same. If you don't know whether you're going
to execute the block even once, then you need to provide defaults, as
you did in your example. That might get a bit tedious, but now we're
talking about helping people use good programming practices (forcing
them to, that is.)

Donn Cave, do...@u.washington.edu

Steve Holden

unread,
Oct 12, 2001, 8:09:56 PM10/12/01
to
"Jyrinx" <jyrinx at mindspring dot com> wrote ...

> Erm, I'm hardly a seasoned hacker, but if I may toss in a few cents ...
>
> > | n = compute_number_of_items()
> > | for i in range(n):
> > | try: process_an_item(items[i])
> > | except: break
> > | update_database('number of items processed = ' % i)
>
[ summary of prior discussion ]

>
> I like Python's for loop, "range()" idiom and all. In any case, I should
> think the above code would be clearer anyway with an explicit check for an
> empty list:
>
> n = compute_number_of_items()
> if n == 0:
> update_database('no items processed')
> else:
> for i in range(n):
> try: process_an_item(items[i])
> except: break
> update_database('number of items processed = ' % i) # (Hmm? I
> thought the % operator was supposed to be used with a string and a
> dictionary? Not that # I would know what I'm talking about ... :-)
>
The left-hand operand is always a string. If it only contains one format
item, the right-hand operand can either be a simple data item or a
one-element tuple (confusingly referred to as a "singleton" in the Python
documentation). If the format items in the string have parenthesised names
in them then the right-hand operand is expected to be a mapping (i.e. to
have a __getattr__() method), and the parenthesised portions are passed as
attribute names to __getattr__().

> Or, if you didn't want to make an extra branch and didn't want the
> uninitialized-i problem, why not just initialize it to 0 before the loop?
>

Slightly bug-prone, but not a bad solution.

regards
Steve
--
http://www.holdenweb.com/

Steve Holden

unread,
Oct 12, 2001, 8:16:00 PM10/12/01
to
"Tim Peters" <t...@zope.com> wrote ...

> [Michael Chermside, on a conditional expression]
> > ...
>
> If people sign off on taking "then" as a new keyword, I think the chances
> are good that we could get
>
> x = if e1 then e2 else e3
>
> into 2.2b1. That's the only obvious spelling, hence the only truly
Pythonic
> way to spell it. Other languages spelling it that way range from Algol-60
> (Guido's first intense language affair) to Haskell.
>
And so perhaps by extension

x = if e1 then e2 elif e3 then e4 else e5

? Yet again starting to look a little Lispish. Of course, eventually people
will be posting asking us to debug

x = if if e1 then e2 else e3 then e4 else e5

and similar. But then every language has its abusers <wink>.

> > hoping-that-less-speed-and-more-thinking-leads-to-a-better-design-
> > ly yours,
>
> less-thinking-will-get-there-faster<wink>-ly y'rs - tim
>

but-there-may-not-be-the-place-you-want-to-get-ly y'rs - steve


Emile van Sebille

unread,
Oct 12, 2001, 8:25:52 PM10/12/01
to

"Tim Peters" <t...@zope.com> wrote in message
news:mailman.1002927732...@python.org...

>
> If people sign off on taking "then" as a new keyword, I think the chances
> are good that we could get
>
> x = if e1 then e2 else e3
>

Would this fully short circuit evaluation of e2 if not e1 (and vv)?

--

Emile van Sebille
em...@fenx.com

---------

James_...@i2.com

unread,
Oct 12, 2001, 8:29:18 PM10/12/01
to

Tim Peters wrote:
>[Michael Chermside, on a conditional expression]
>> ...
>> As before, if anyone else feels strongly that they'd like to contribute
>> (other than the excellent comments several folks already made), they
>> should email me.
>
>If people sign off on taking "then" as a new keyword, I think the chances
>are good that we could get
>
> x = if e1 then e2 else e3
>
>into 2.2b1.

Looks good to me.

Jim

Jyrinx

unread,
Oct 12, 2001, 9:18:03 PM10/12/01
to
> | Or, if you didn't want to make an extra branch and didn't want the
> | uninitialized-i problem, why not just initialize it to 0 before the
loop?
>
> Good practice for sure, but I think the point may have been that
> you shouldn't have to go to so much extra trouble, for safe code.
> You pretty much had to anticipate the problem, to think to make
> those provisions for it, and if 0 items is an exceptional case,
> you'd be very likely to to neglect them. Once this potential occurs
> to you, it's very easy to solve that problem.

Okay, granted. Somehow, though, I doubt C(++) in general is much better in
terms of being "natural" like this ... :-)

(and I would guess that the veteran Python junkie would get used to this
sort of initialization, no?)

> Here's an idea - suppose the block has its own scope! Now a reference
> to "i" is illegal outside the block. More or less like global scope
> vs. function local - if i was assigned to prior to the block, then the
> binding is inherited by the block, but new names are bound in the block
> scope. Not just the for variable, any assignment - after all, the
> problem is exactly the same. If you don't know whether you're going
> to execute the block even once, then you need to provide defaults, as
> you did in your example. That might get a bit tedious, but now we're
> talking about helping people use good programming practices (forcing
> them to, that is.)

Well, this is precisely what happens in C, right (for variables declared in
the loop)? Personally, I like that kind of strict scoping - it indicates
that a variable introduced inside a loop is there on a temporary basis, and
has no purpose being used outside of it. If the programmer must initialize
the variable before the loop because he intends to use it after the loop, it
makes it clearer to a reader, anyway, since the reader knows immediately
that the loop iterator is somehow an important part of the result of the
loop.

Peter Hansen

unread,
Oct 12, 2001, 10:36:15 PM10/12/01
to
"Tim Peters" <t...@zope.com> wrote:
> > If people sign off on taking "then" as a new keyword, I think the chances
> > are good that we could get
> >
> > x = if e1 then e2 else e3

You mean it isn't already a keyword?

<on behalf of those who subconsciously thought it was...>

+1 on proposal

--
----------------------
Peter Hansen, P.Eng.
pe...@engcorp.com

Tim Peters

unread,
Oct 12, 2001, 10:34:05 PM10/12/01
to
> x = if e1 then e2 else e3

[Emile van Sebille]


> Would this fully short circuit evaluation of e2 if not e1

Of course. It would be "the same as"

if e1:
__unspellable_name__ = e2
else:
__unspellable_name__ = e3
x = __unspellable_name__

> (and vv)?

It wouldn't evaluate "vv" at all <wink>.

nor-is-it-limited-to-"x"-etc-ly y'rs - tim


Tim Peters

unread,
Oct 12, 2001, 10:29:48 PM10/12/01
to
[Tim]

> If people sign off on taking "then" as a new keyword, I think
> the chances are good that we could get
>
> x = if e1 then e2 else e3
>
> into 2.2b1. That's the only obvious spelling, hence the only truly
> Pythonic way to spell it. Other languages spelling it that way range
> from Algol-60 (Guido's first intense language affair) to Haskell.

[Steve Holden]


> And so perhaps by extension
>
> x = if e1 then e2 elif e3 then e4 else e5
>
> ?

I expect there's scant chance of that, just what I said at the top.

> Yet again starting to look a little Lispish.

(cond (e1 e2) (e3 e4) (t e5))

isn't on the table either.

> Of course, eventually people will be posting asking us to debug
>
> x = if if e1 then e2 else e3 then e4 else e5
>
> and similar. But then every language has its abusers <wink>.

You don't need to reply to them. After nearly a decade of this, it occurred
to me that not every dumb-ass idea needs its day in court <wink>.

only-the-dumb-ass-ideas-you-like-ly y'rs - tim


John Roth

unread,
Oct 13, 2001, 12:03:18 AM10/13/01
to

"Jyrinx" <jyrinx at mindspring dot com> wrote in message
news:9q84ob$1ls$1...@nntp9.atl.mindspring.net...

>
> Well, this is precisely what happens in C, right (for variables declared
in
> the loop)? Personally, I like that kind of strict scoping - it indicates
> that a variable introduced inside a loop is there on a temporary basis,
and
> has no purpose being used outside of it. If the programmer must initialize
> the variable before the loop because he intends to use it after the loop,
it
> makes it clearer to a reader, anyway, since the reader knows immediately
> that the loop iterator is somehow an important part of the result of the
> loop.

Yup. That's exactly why the original example that started this branch is
poor programming practice, in general. In the way it was used, it looks like
a debugging statement, and there is no good way in Python to say "run this
code after the loop, but only if the loop executed at least once."

John Roth

John Roth

unread,
Oct 13, 2001, 12:07:55 AM10/13/01
to

"Tim Peters" <t...@zope.com> wrote in message
news:mailman.1002927732...@python.org...
> [Michael Chermside, on a conditional expression]
> > ...

> If people sign off on taking "then" as a new keyword, I think the chances


> are good that we could get
>
> x = if e1 then e2 else e3
>
> into 2.2b1. That's the only obvious spelling, hence the only truly
Pythonic
> way to spell it. Other languages spelling it that way range from Algol-60
> (Guido's first intense language affair) to Haskell.

I've got no problem with it. I don't think I've ever named a variable
'then' in my life. Even in assembler.

John Roth


Chris Dutton

unread,
Oct 13, 2001, 12:53:34 AM10/13/01
to
in article 7xlmiiv...@ruckus.brouhaha.com, Paul Rubin at
phr-n...@nightsong.com wrote on 10/11/01 4:11 AM:

> Chris Dutton <ch...@cmb-enterprises.com> writes:
>> The example I saw somewhere that I liked was
>>
>> if something as x:
>> do_something_to(x)
>
> That's ok too, as long as the comparison doesn't have to be with zero:
> if (something as x) == 3:
> do_something_to(x)

Just occurred to me, this kind of aliasing could be helpful elsewhere. Say
in list comprehensions perhaps?

Alex Martelli

unread,
Oct 13, 2001, 4:59:38 AM10/13/01
to
Huaiyu Zhu wrote:

>>while data.set(file.readline()) != 'end':
>> process(data.get())
>
> Alex, what's your opinion comparing these to the following?
>
> while line = file.xreadlines(); line != 'end':
> etcetc(line)
>
> I'm pushing for this because it is not just syntactic suguar. It gives

Your approach is indeed far more general -- I just showed somewhat-clunky
syntax that has the advantage of working right now (and ever since the Dawn
of Python) when one is transliterating code from other languages (I
wouldn't use it in code meant to be idiomatically Pythonic, or Pythonically
idiomatic). However, the ability to have arbitrary statements as part of
an "expression" may be TOO general for comfort -- right now I can rely on
the fact that an expression can never rebind my local variables (and this
for example makes eval usable where exec might not be), the generalization
would take such guarantees away. A much more wary look at the trade-offs
is therefore surely warranted.


Alex

David Glasser

unread,
Oct 13, 2001, 4:47:52 PM10/13/01
to
Paul Rubin <phr-n...@nightsong.com> wrote:

> Just today I had a bug that went something like:
>
> n = compute_number_of_items()
> for i in range(n):
> try: process_an_item(items[i])
> except: break
> update_database('number of items processed = ' % i)

[but for n = 0, i never gets defined]

I'm confused. Won't this give the wrong answer, anyway? If you do
process all n correctly, i will be set to n-1. So you'll have to log
"i+1". And by this point you might as well just increment a variable
every time you process an item correctly, which is a lot clearer than
using the value of a loop index outside of the loop, in my opinion.

--
David Glasser
ne...@davidglasser.net http://www.davidglasser.net/

Paul Rubin

unread,
Oct 13, 2001, 8:55:28 PM10/13/01
to
ne...@davidglasser.net (David Glasser) writes:
> > Just today I had a bug that went something like:
> >
> > n = compute_number_of_items()
> > for i in range(n):
> > try: process_an_item(items[i])
> > except: break
> > update_database('number of items processed = ' % i)
> [but for n = 0, i never gets defined]
>
> I'm confused. Won't this give the wrong answer, anyway? If you do
> process all n correctly, i will be set to n-1. So you'll have to log
> "i+1". And by this point you might as well just increment a variable
> every time you process an item correctly, which is a lot clearer than
> using the value of a loop index outside of the loop, in my opinion.

In that example it should have said range(1,n+1), I guess. The actual
code with the bug worked a little bit differently-- the example just
abstracted it, incorrectly it turned out. (The real code stored the
number of the last item processed, not the number of items processed,
and originally read the number from the database).

Joal Heagney

unread,
Oct 13, 2001, 10:11:09 PM10/13/01
to
Tim Peters wrote:

> If people sign off on taking "then" as a new keyword, I think the chances
> are good that we could get
>
> x = if e1 then e2 else e3
>
> into 2.2b1. That's the only obvious spelling, hence the only truly Pythonic
> way to spell it. Other languages spelling it that way range from Algol-60
> (Guido's first intense language affair) to Haskell.

> less-thinking-will-get-there-faster<wink>-ly y'rs - tim

Well I just did another grep -r "then" *.py on /usr/lib/python2.1, and I
couldn't find any use of "then" outside of comments.
--
Joal Heagney is: _____ _____
/\ _ __ __ _ | | _ ___ |
/__\|\ || ||__ |\ || |___|/_\|___] |
/ \ \_||__ ||___| \_|! | | \ \ !

Paul Rubin

unread,
Oct 13, 2001, 10:32:04 PM10/13/01
to
"Tim Peters" <t...@zope.com> writes:
> If people sign off on taking "then" as a new keyword, I think the chances
> are good that we could get
>
> x = if e1 then e2 else e3
>
> into 2.2b1. That's the only obvious spelling, hence the only truly Pythonic
> way to spell it. Other languages spelling it that way range from Algol-60
> (Guido's first intense language affair) to Haskell.

This sounds fine to me.

Tim Peters

unread,
Oct 14, 2001, 3:50:36 PM10/14/01
to
[Tim]

> If people sign off on taking "then" as a new keyword, I think
> the chances are good that we could get
>
> x = if e1 then e2 else e3
>
> into 2.2b1. That's the only obvious spelling, hence the only
> truly Pythonic way to spell it. Other languages spelling it that
> way range from Algol-60 (Guido's first intense language affair) to
> Haskell.

[Paul Rubin, among others of similar mind]


> This sounds fine to me.

Alas, it didn't to Python's parser -- one-token lookahead isn't enough to
distinguish

if 1:

from

if 1 then 2 else 3

let alone

if a + b / c:

from

if a + b / c then 2 else 3

etc.

and Python won't grow anything a simple parser can't sort out.

Everything's cool if parens are required around a conditional expression,
though, in which case:

x = if e1 then e2 else e3 + 1 # SyntaxError
x = (if e1 then e2 else e3) + 1 # cool
x = (if e1 then e2 else e3 + 1) # cool
x = if e1 then e2 else e3 # SyntaxError
x = (if e1 then e2 else e3) # cool
x = if if e1 then e2 else e3 then e4 else e5 # SyntaxError
x = (if (if e1 then e2 else e3) then e4 else e5) # cool

Seems a mixed bag, but I'm more interested in readability and the
functionality than in minimizing keystrokes; requiring parens doesn't hurt
the goals I care about.

implemented-but-not-checked-in-ly y'rs - tim


Paul Rubin

unread,
Oct 14, 2001, 4:34:26 PM10/14/01
to
"Tim Peters" <tim...@home.com> writes:
> Everything's cool if parens are required around a conditional expression,
> though, in which case:
>
> x = if e1 then e2 else e3 + 1 # SyntaxError
> x = (if e1 then e2 else e3) + 1 # cool
> x = (if e1 then e2 else e3 + 1) # cool
> x = if e1 then e2 else e3 # SyntaxError
> x = (if e1 then e2 else e3) # cool
> x = if if e1 then e2 else e3 then e4 else e5 # SyntaxError
> x = (if (if e1 then e2 else e3) then e4 else e5) # cool
>
> Seems a mixed bag, but I'm more interested in readability and the
> functionality than in minimizing keystrokes; requiring parens doesn't hurt
> the goals I care about.

It's more readable with the parentheses anyway.

John Roth

unread,
Oct 14, 2001, 7:08:44 PM10/14/01
to

"Paul Rubin" <phr-n...@nightsong.com> wrote in message
news:7xu1x22...@ruckus.brouhaha.com...

Exactly my thought. Less chance for the eye seeing what it wants to.

John Roth


DeepBlue

unread,
Oct 14, 2001, 7:47:44 PM10/14/01
to

"Tim Peters" <tim...@home.com> wrote in message
news:mailman.1003089072...@python.org...

>
> x = if e1 then e2 else e3 + 1 # SyntaxError
> x = (if e1 then e2 else e3) + 1 # cool

Much better:
x = if e1 then (e2) else (e3)
note that (e2) and (e3) stand for any operation:
The problem with: x = (if e1 then e2 else e3) + 1 # cool
is that it lacks potential of generalization.
x = if e1 then (e2) else (e3)
does give the user more freedom.

> x = (if e1 then e2 else e3 + 1) # cool

but not clear.


> x = if e1 then e2 else e3 # SyntaxError

no reason for error


> x = (if e1 then e2 else e3) # cool

shuold be euivalent to above


> x = if if e1 then e2 else e3 then e4 else e5 # SyntaxError
> x = (if (if e1 then e2 else e3) then e4 else e5) # cool

But
x = if (if e1 then e2 else e3) then e4 else e5 # should be cool too
and so


x = (if (if e1 then e2 else e3) then e4 else e5)

with my idea:
x = (if (if e1 then (e2) else (e3)) then (e4) else (e5))
or
x = if (if e1 then (e2) else (e3)) then (e4) else (e5)
should be equivalent.
If the original posting passes Python will have its first confusing moment.
x = if e1 then (e2) else (e3)
and
x = (if e1 then (e2) else (e3))
should be equivalent and they preserve clarity.
DB


Tim Peters

unread,
Oct 14, 2001, 10:43:45 PM10/14/01
to
[DeepBlue]

> Much better:
> x = if e1 then (e2) else (e3)

You're apparently responding to an edited reply, and didn't read the thread
from its start: surrounding parens are required else you don't get this
form of conditional expression at all. It's not a question of whether to
require surrounding parens or not; the latter isn't an option, due to the
limitations of one-token lookahead parsing (read the thread from the start).

> note that (e2) and (e3) stand for any operation:

e1, e2 and e3 in the original are any expressions (formally, 'test' in the
Python grammar). I don't know what "operation" means to you, or why you
think adding some parentheses *could* make a semantic difference. In the
formal syntax, the production for atom changes from

atom: '(' [testlist] ')' | '[' [listmaker] ']' | '{' [dictmaker] '}' |
'`' testlist '`' | NAME | NUMBER | STRING+

to

atom: '(' ([testlist] | cond_expr) ')' | ... [the rest is unchanged]

cond_expr: 'if' test 'else' test 'then' test

> The problem with: x = (if e1 then e2 else e3) + 1 # cool
> is that it lacks potential of generalization.

Generalization to what? Please be specific. Stuff like

x = (if a+b/sqrt(3) then 3**f(5, 3)- 12 else ",".join(list) + ":\n")

is fine. If you *want* to stick extra parens around the e2 and e3
expressions, that's fine too, but not required.

> x = if e1 then (e2) else (e3)
> does give the user more freedom.

Sorry, I can't see how.

>> x = (if e1 then e2 else e3 + 1) # cool

> but not clear.

Because? It's no more or less general than, e.g.,

x = e1 and e2

today, of which, e.g.,

x = y + 1 or z + 1

is a specific instance.

>> x = if e1 then e2 else e3 # SyntaxError

> no reason for error

Read the thread.

> ... [more much the same snipped] ...

> with my idea:
> x = (if (if e1 then (e2) else (e3)) then (e4) else (e5))

This is legit under the proposal.

> or
> x = if (if e1 then (e2) else (e3)) then (e4) else (e5)

But this isn't.

> should be equivalent.
> If the original posting

If you haven't even read the first msg in this thread alone, I shudder to
imagine what "original" means to you <wink>.

> passes Python will have its first confusing moment.
> x = if e1 then (e2) else (e3)
> and
> x = (if e1 then (e2) else (e3))
> should be equivalent and they preserve clarity.

The latter form would be accepted, but not the former (and the former cannot
be accepted, which is a question of parser technology, not of taste).


Paul Rubin

unread,
Oct 14, 2001, 11:19:55 PM10/14/01
to
"Tim Peters" <tim...@home.com> writes:
> > x = if e1 then (e2) else (e3)
> > and
> > x = (if e1 then (e2) else (e3))
> > should be equivalent and they preserve clarity.
>
> The latter form would be accepted, but not the former (and the former cannot
> be accepted, which is a question of parser technology, not of taste).

How did Algol 60 deal with this?

Greg Ewing

unread,
Oct 14, 2001, 11:25:49 PM10/14/01
to
Paul Rubin wrote:
>
> (The real code stored the
> number of the last item processed, not the number of items processed

In that case, if there are 0 items, there is no "last
item processed", so that's going to be a special case
anyway.

--
Greg Ewing, Computer Science Dept, University of Canterbury,
Christchurch, New Zealand
To get my email address, please visit my web page:
http://www.cosc.canterbury.ac.nz/~greg

Paul Rubin

unread,
Oct 14, 2001, 11:47:16 PM10/14/01
to
Greg Ewing <gr...@cosc.canterbury.ac.nz> writes:
> > (The real code stored the
> > number of the last item processed, not the number of items processed
>
> In that case, if there are 0 items, there is no "last
> item processed", so that's going to be a special case
> anyway.

The last item processed in that case is the last item processed by
a previous run of the program.

Rainer Deyke

unread,
Oct 15, 2001, 12:14:12 AM10/15/01
to
"Tim Peters" <tim...@home.com> wrote in message
news:mailman.1003113854...@python.org...

> You're apparently responding to an edited reply, and didn't read the
thread
> from its start: surrounding parens are required else you don't get this
> form of conditional expression at all. It's not a question of whether to
> require surrounding parens or not; the latter isn't an option, due to the
> limitations of one-token lookahead parsing (read the thread from the
start).

Actually, it would probably be possible to make the parens optional in all
cases except where 'if' is the first token of the expression.

x = if a then b else c # legal
if a then b else c # syntax error

The required changes in the grammar are quite small:

1. Replace all rhs instances of "testlist" with "any_expression",
*except* the first one in "expr_stmt".
2. Add the following production: "any_expression: testlist
| 'if' any_expression 'then' any_expression 'else' any_expression".

(This still doesn't allow unadorned conditional expressions in places where
"testlist" is not used, such as function arguments.)


--
Rainer Deyke (ro...@rainerdeyke.com)
Shareware computer games - http://rainerdeyke.com
"In ihren Reihen zu stehen heisst unter Feinden zu kaempfen" - Abigor


Chris Tavares

unread,
Oct 15, 2001, 2:16:12 AM10/15/01
to

"Tim Peters" <tim...@home.com> wrote in message
news:mailman.1003089072...@python.org...
> [Tim]
[... snip ... ]

> Alas, it didn't to Python's parser -- one-token lookahead isn't enough to
> distinguish
>
> if 1:
>
> from
>
> if 1 then 2 else 3
>
[ ... snip ... ]

> Everything's cool if parens are required around a conditional expression,
> though, in which case:
>
> x = if e1 then e2 else e3 + 1 # SyntaxError
> x = (if e1 then e2 else e3) + 1 # cool
> x = (if e1 then e2 else e3 + 1) # cool
> x = if e1 then e2 else e3 # SyntaxError
> x = (if e1 then e2 else e3) # cool
> x = if if e1 then e2 else e3 then e4 else e5 # SyntaxError
> x = (if (if e1 then e2 else e3) then e4 else e5) # cool
>
> Seems a mixed bag, but I'm more interested in readability and the
> functionality than in minimizing keystrokes; requiring parens doesn't hurt
> the goals I care about.
>

May I be the first to say - ICK!

I have enough political problems trying to get people I know to try python
out - adding a wart like this ( and requiring parens on this one, and only
one expression is really a wart!) and trying to explain it to newbies
doesn't strike me as a winner, and I've never really pined for this as an
experienced user.

Question - what happens with:

x = (if e1 then e2 else e3,) # <--- note trailing comma

Should be a 1 element tuple, yes? What happens? Or would you have to write:

x = ((if e1 then e2 else e3),)

That's just ugly.

-Chris

Paul Rubin

unread,
Oct 15, 2001, 2:32:19 AM10/15/01
to
"Chris Tavares" <christoph...@earthlink.net> writes:
> Question - what happens with:
>
> x = (if e1 then e2 else e3,) # <--- note trailing comma
>
> Should be a 1 element tuple, yes? What happens? Or would you have to write:
>
> x = ((if e1 then e2 else e3),)
>
> That's just ugly.

I think you could write
x = (if e1 then e2 else e3),

Michael Abbott

unread,
Oct 15, 2001, 2:54:00 AM10/15/01
to
"Rainer Deyke" <ro...@rainerdeyke.com> wrote in
news:ooty7.61655$w62.37...@news1.denver1.co.home.com:

> Actually, it would probably be possible to make the parens optional in
> all cases except where 'if' is the first token of the expression.
>
> x = if a then b else c # legal
> if a then b else c # syntax error
>
> The required changes in the grammar are quite small:
>
> 1. Replace all rhs instances of "testlist" with "any_expression",
> *except* the first one in "expr_stmt".
> 2. Add the following production: "any_expression: testlist
> | 'if' any_expression 'then' any_expression 'else' any_expression".

Yes! And in this particular case it really doesn't matter anyway, since an
isolated if expression is indistinguishable in effect from an isolated if
statement.

Oh, while we're being concrete about the syntax, don't forget to allow elif
in conditional expressions!

Michael Abbott

unread,
Oct 15, 2001, 2:34:54 AM10/15/01
to
Michael,

> I submitted a proposed PEP not long ago, and got a lot of comments.
> Unfortunately, I didn't see any consensus begin to emerge, at least not
> one that I could recognize. So I decided I should put it away for a
> month or so, then come back with a fresh mind to create the version I
> actually submitted. It's my theory (untested, of course) that this will
> result in a better initial PEP and thus a better chance of acceptance.

My though on your pre PEP was that it was a discussion document, and not
really a Python extension proposal. There still seems to be a bit of
argument about the syntax, I can't quite remember where we got to. I think
we ended with allowing

if e1: e2 else: e3

to be an expression (I'd prefer to grab 'then' as a keywork, and write

if e1 then e2 else e3

but the penalty of a keywork is a relatively high hurdle).


Why not reopen the discussion (need a new thread for this!), choose one
syntax only, and write a very short PEP which simply proposes that syntax.

I've forgotten what the options were; I suppose one way to repoen things
would be to re-post your pre PEP.

Regards,
Michael

Ian Parker

unread,
Oct 15, 2001, 3:33:02 AM10/15/01
to
In article <mailman.1003089072...@python.org>, Tim Peters
<tim...@home.com> writes

Presumably this wouldn't lead to any misleading syntax error
identification problems with multiple lines? For example multi-line
versions of these new 'if' expressions, or where a trailing '{' has
been left at the end of a line preceding a normal 'if' statement.

Would sensible syntax errors and line numbers still be reported?

Not that I leave many trailing "("s. but if I were to do so, I'd like to
have as much help as possible tracking them down.
--
Ian Parker

Ian Parker

unread,
Oct 15, 2001, 3:33:03 AM10/15/01
to
In article <7xitdha...@ruckus.brouhaha.com>, Paul Rubin <phr-
n20...@nightsong.com> writes

to excess, and with a more complicated parser, I imagine:


Because statements are expressions in Algo68, the 'if' clause returns a
value, and can be used as both a statement and an expression, and either
can be squeezed onto one line or spread across multiple lines.

But there are two ways of writing the 'if' clause:

'bold' style: if v then w elif x then y else z fi
'brief' style: ( v > | w |: x | y | z)

In both cases the elif ('|:') can be repeated as many times as you can
face it, and both the elif and else clauses are optional

Doesn't help at all does it? However, it does suggest the question:
Would this new Python conditional expression support:

--
Ian Parker

Paul Rubin

unread,
Oct 15, 2001, 3:43:31 AM10/15/01
to
Ian Parker <par...@gol.com> writes:
> >How did Algol 60 deal with this?
>
> to excess, and with a more complicated parser, I imagine:
>
>
> Because statements are expressions in Algo68, the 'if' clause returns a
> value, and can be used as both a statement and an expression, and either
> can be squeezed onto one line or spread across multiple lines.

Algol 60 wasn't anything like Algol 68 though. Its parser had to have
been pretty simple.

Andrew Dalke

unread,
Oct 15, 2001, 3:48:16 AM10/15/01
to
Chris Tavares wrote:
>May I be the first to say - ICK!

I'll second that nomination.

It looks ugly, and doesn't solve any problems I have.
I *like*

if e1:
x = e2
else:
x = e3

Makes it easy to see what goes on when e1 is true or false.
Take Uncle Tim's example code

x = (if a+b/sqrt(3) then 3**f(5, 3)- 12 else ",".join(list) + ":\n")

and compare its readability to

if a+b/sqrt(3):
x = 3**f(5, 3) - 12
else:
x = ",".join(list) + ":\n"

I can easily understand the second. The first takes effort.

There's talk of generalization. But more likely the expansion of a
one-liner like the above is to add more statements to a branch, as
in something like:

if a+b/sqrt(3):
count = count + 1
x = 3**f(5, 3) - 12
else:
spam *= count
x = ",".join(list) + ":\n"

With the one-liner form, translation to the normal Python if/else
statement calls for a lot of code changes.

I tried looking through the thread in its various subject names.
I couldn't figure out what was the driving reason for this idea.
(Other than as a replacement for C's ?: ternary operator.)
Enlightment, anyone?

Andrew
da...@dalkescientific.com

DeepBlue

unread,
Oct 15, 2001, 9:38:42 AM10/15/01
to
Tim
For some reason the thread on this topic started with your edited reply, and
I could not get anything earlier. Maybe a problem with the news server I
use.
But I see your point now. Apologies for the misunderstanding.
DB

"Tim Peters" <tim...@home.com> wrote in message

news:mailman.1003113854...@python.org...

Markus Schaber

unread,
Oct 15, 2001, 10:17:02 AM10/15/01
to
Hi,

Steve Holden <sho...@holdenweb.com> schrub:

> And so perhaps by extension
>
> x = if e1 then e2 elif e3 then e4 else e5

Looks good and readable.

+1 from me.

> ? Yet again starting to look a little Lispish. Of course, eventually
> people will be posting asking us to debug


>
> x = if if e1 then e2 else e3 then e4 else e5
>

> and similar. But then every language has its abusers <wink>.

I think it is not worse than other weird one-liners we already had here
:-)

markus
--
You don't have to be Microsoft to suck... but it helps.
(Tim Hammerquist in comp.lang.python)

Ralph Corderoy

unread,
Oct 15, 2001, 1:57:16 PM10/15/01
to
Hi Tim,

> implemented-but-not-checked-in-ly y'rs - tim

Don't check it in. It's horrible. I'm all for a ?: in Python using
some notation or other but requiring parenthesis around just this kind
of expression isn't on.

It's non-obvious and distinct from other areas. It is surprising!

Cheers,


Ralph.

James_...@i2.com

unread,
Oct 15, 2001, 1:30:35 PM10/15/01
to

Paul Rubin wrote:

>"Tim Peters" <tim...@home.com> writes:
>> Everything's cool if parens are required around a conditional
expression,
>> though, in which case:
>>
>> x = if e1 then e2 else e3 + 1 # SyntaxError
>> x = (if e1 then e2 else e3) + 1 # cool
>> x = (if e1 then e2 else e3 + 1) # cool
>> x = if e1 then e2 else e3 # SyntaxError
>> x = (if e1 then e2 else e3) # cool
>> x = if if e1 then e2 else e3 then e4 else e5 # SyntaxError
>> x = (if (if e1 then e2 else e3) then e4 else e5) # cool
>>
>> Seems a mixed bag, but I'm more interested in readability and the
>> functionality than in minimizing keystrokes; requiring parens doesn't
hurt
>> the goals I care about.
>
>It's more readable with the parentheses anyway.

I agree.

Jim

Ben Wolfson

unread,
Oct 15, 2001, 2:07:07 PM10/15/01
to
In article <9qf81s$lut$1...@inputplus.demon.co.uk>, "Ralph Corderoy"
<ra...@inputplus.demon.co.uk> wrote:

Furthermore the use of "then" in this case but not in the more general
if: elif: else: case is potentially confusing.

--
Barnabas T. Rumjuggler
Clock zero: You are a pirate masquerading as a counselor.

John Roth

unread,
Oct 15, 2001, 2:27:54 PM10/15/01
to

"Ian Parker" <par...@gol.com> wrote in message
news:apXvDKAP...@gol.com...

> In article <7xitdha...@ruckus.brouhaha.com>, Paul Rubin <phr-
> n20...@nightsong.com> writes
> >"Tim Peters" <tim...@home.com> writes:
> >> > x = if e1 then (e2) else (e3)
> >> > and
> >> > x = (if e1 then (e2) else (e3))
> >> > should be equivalent and they preserve clarity.
> >>
> >> The latter form would be accepted, but not the former (and the former
cannot
> >> be accepted, which is a question of parser technology, not of taste).
> >
> >How did Algol 60 deal with this?
>
> to excess, and with a more complicated parser, I imagine:

Actually, there was a quite good book on one company's Algol 60
implementation (called "Algol 60 Implementation", I believe), that
showed a recursive descent parser, with all of the parser and interpreter
functions diagrammed out. This was before there was a whole lot
of parser theory to go by...

John Roth


John Roth

unread,
Oct 15, 2001, 2:40:07 PM10/15/01
to

"Tim Peters" <tim...@home.com> wrote in message
news:mailman.1003089072...@python.org...

> [Tim]
> > If people sign off on taking "then" as a new keyword, I think
> > the chances are good that we could get
> >
> > x = if e1 then e2 else e3
> >
> > into 2.2b1. That's the only obvious spelling, hence the only
> > truly Pythonic way to spell it. Other languages spelling it that
> > way range from Algol-60 (Guido's first intense language affair) to
> > Haskell.
>
> [Paul Rubin, among others of similar mind]
> > This sounds fine to me.
>
> Alas, it didn't to Python's parser -- one-token lookahead isn't enough to
> distinguish
>
> if 1:
>
> from
>
> if 1 then 2 else 3
>

Huh? The purpose of the new syntax is to have a conditional
facility within an expression. If a new line begins with the keyword
'if', then that is a statement. A conditional if only makes sense _inside_
an expression, hence it doesn't look like there is an issue.

A bigger issue from a usability standpoint is the lack of a
clear end to the scope of a given 'if', leading to the infamous
dangling 'else' problem.

John Roth


It is loading more messages.
0 new messages