Abstract
This PEP proposes adding an optional "do" clause to the beginning
of the while loop to make loop code clearer and reduce errors
caused by code duplication.
Motivation
It is often necessary for some code to be executed before each
evaluation of the while loop condition. This code is often
duplicated outside the loop, as setup code that executes once
before entering the loop:
<setup code>
while <condition>:
<loop body>
<setup code>
The problem is that duplicated code can be a source of errors if
one instance is changed but the other is not. Also, the purpose
of the second instance of the setup code is not clear because it
comes at the end of the loop.
It is possible to prevent code duplication by moving the loop
condition into a helper function, or an if statement in the loop
body. However, separating the loop condition from the while
keyword makes the behavior of the loop less clear:
def helper(args):
<setup code>
return <condition>
while helper(args):
<loop body>
This last form has the additional drawback of requiring the loop's
else clause to be added to the body of the if statement, further
obscuring the loop's behavior:
while True:
<setup code>
if not <condition>: break
<loop body>
This PEP proposes to solve these problems by adding an optional
clause to the while loop, which allows the setup code to be
expressed in a natural way:
do:
<setup code>
while <condition>:
<loop body>
This keeps the loop condition with the while keyword where it
belongs, and does not require code to be duplicated.
Syntax
The syntax of the while statement
while_stmt : "while" expression ":" suite
["else" ":" suite]
is extended as follows:
while_stmt : ["do" ":" suite]
"while" expression ":" suite
["else" ":" suite]
Semantics of break and continue
In the do-while loop the break statement will behave the same as
in the standard while loop: It will immediately terminate the loop
without evaluating the loop condition or executing the else
clause.
A continue statement in the do-while loop will behave somewhat
differently than in the standard while loop. Instead of jumping
back to the loop condition, it will jump to the beginning of the
first suite of the loop. This is to ensure that the setup code
has a chance to do its job before the condition is evaluated.
Future Statement
Because of the new keyword "do", the statement
from __future__ import do_while
will initially be required to use the do-while form.
Implementation
The first implementation of this PEP can compile the do-while loop
as an infinite loop with a test that exits the loop.
Copyright
This document is placed in the public domain.
I'm interested, but I can't come up with a scenario where the loop couldn't
be rewritten, except for do..until loops that must execute at least once,
which require the first loop iteration to be placed before a while loop.
And for that scenario, I would propose a simple "until" loop construct that
is guaranteed to execute once before evaluation:
# Old way
MakeMoney()
while Poor():
MakeMoney()
# New way
until not Poor():
MakeMoney()
The above example assumes one must MakeMoney() before running the Poor()
test ;)
Python programmers would just have to understand that the "until" construct
executes once before evaluation. Or maybe it could be named something more
obvious. "AfterWhile" - heh - no pun intended.
> --
> http://mail.python.org/mailman/listinfo/python-list
I was just doing this yesterday:
print "Type 'exit' to quit..."
line = raw_input("> ")
while line != "exit":
process_line(line)
line = raw_input("> ")
With the new PEP it would look like this, I think:
print "Type 'exit' to quit..."
do:
line = raw_input("> ")
while line != "exit":
process_line(line)
Of course, I only had one line of setup code so the PEP didn't actually
shorten it a lot, but I can imagine what this would do to bigger examples.
I rather like it.
Dirk Gerrits
> Can you provide an example snippit?
>
> I'm interested, but I can't come up with a scenario where the loop
> couldn't be rewritten, except for do..until loops that must execute at
> least once, which require the first loop iteration to be placed before a
> while loop.
Those "can be rewritten" too, of course.
In general, the proposed syntax:
do:
setup
while condition:
remainder
has exactly the same semantics as:
while True:
setup
if not condition: break
remainder
so the rewrite is always trivially easy. The PEP claims the current
form is unreadable -- and that syntax-sugar issue is all that needs
to be discussed (as well as choice of new keyword -- if the new PEP
was accepted I'd rather have the more readable 'loop' instead of
the totally obscure 'do').
> And for that scenario, I would propose a simple "until" loop construct
> that is guaranteed to execute once before evaluation:
>
> # Old way
> MakeMoney()
> while Poor():
> MakeMoney()
>
> # New way
> until not Poor():
> MakeMoney()
Rewritable as:
while True:
MakeMoney()
if not Poor(): break
> The above example assumes one must MakeMoney() before running the Poor()
> test ;)
>
> Python programmers would just have to understand that the "until"
> construct executes once before evaluation. Or maybe it could be named
> something more obvious. "AfterWhile" - heh - no pun intended.
I find myself quite grateful that the designer of Python will never
allow anything as absurd as your proposal -- an unreadable "backwards"
ordering (condition appears before but is tested after) AND a new
keyword, all to "solve" *HALF* of an (arguable) problem, when it's
just as easy, as the PEP shows, to solve ALL of it WITHOUT imposing
"out of order" sequencing of source code vs execution order!
Alex
After grepping through a few thousand lines of Python code, I found
only one use of the "while 1"..."break" construct (which I assume is
what do...while intends to replace), which was the main loop in my
text adventure game.
while 1:
# ...
if not getYN("You are now dead. Would you like to play again
(Y/N)?"):
break
if getYN("Would you like to read the intro again (Y/N)?"):
intro()
I'm not sure what the equivalent do...while loop would be.
> And for that scenario, I would propose a simple "until" loop construct that
> is guaranteed to execute once before evaluation:
>
> # Old way
> MakeMoney()
> while Poor():
> MakeMoney()
>
> # New way
> until not Poor():
> MakeMoney()
>
> The above example assumes one must MakeMoney() before running the Poor()
> test ;)
>
> Python programmers would just have to understand that the "until" construct
> executes once before evaluation. Or maybe it could be named something more
> obvious. "AfterWhile" - heh - no pun intended.
TI-8x BASIC (the only language I know of that puts posttest loop
conditions at the beginning) uses
:Repeat not Poor()
:MakeMoney
:End
(Actually, this isn't valid code, because there are no user-defined
functions and no identifiers longer than 8 chars, but this is
irrelevant.)
In future Python, this could be written
repeat not Poor():
MakeMoney()
My personal preferred syntax is
posttest while Poor():
MakeMoney()
Frankly, this doesn't do nearly enough to make me interested in
cluttering
the language, and the "if <condition>: break" figure is sufficiently
well
entrenched in a ***lot*** of languages that it's hardly a problem. As
long as a loop starts with "while 1:" or "while True:", you expect to
see
a break and look for it.
-1
John Roth
At one point, quite a few BASIC and Pascal flavors had a repeat..until or
do..while loop construct. It seems that it faded away, and I'm not sure why.
"posttest while" is as good as anything. It introduces only one key word, is
clear, and doesn't force the looping construct to be split into separate
blocks. Part of the elegance of Python is that the indentation level tells a
lot about the execution path. The do/while PEP would break that rule.
> -----Original Message-----
> From: python-l...@python.org [mailto:python-l...@python.org]
> --
> http://mail.python.org/mailman/listinfo/python-list
Enough of these requests get satisfied, we may as well go to committee.
Python will be dead by then, even if all involved don't really know it.
The kitchen sink hits the language with a loud clank, bounces around,
everyone dodges, flees the neighborhood.
Python ain't broken. Please don't fix it.
C//
> This PEP proposes to solve these problems by adding an optional
> clause to the while loop, which allows the setup code to be
> expressed in a natural way:
>
> do:
> <setup code>
> while <condition>:
> <loop body>
>
> This keeps the loop condition with the while keyword where it
> belongs, and does not require code to be duplicated.
My immediate intuition, when presented with the above syntax, is to
assume that the actual logic of the loop occurs in <setup code>, for two
reasons:
1. It follows from the meaning of 'do' and 'while': "I'm eating lunch
('do') while the diner is serving it ('while')." The above syntax
corresponds with: "I'm in the diner ('do'), while they are serving lunch
('while') and I'm eating lunch ('loop body')." The second example makes
sense, but the first one is more intuitive and natural.
2. Most major languages that implement a post-test loop include the
<loop body> between 'do' and 'while' (or their equivalents). People new
to Python but familar with such languages will expect this.
A closer examination of the code in <setup code> and <loop body> will of
course indicate what is happening. But why create dissonance? My
suggestion would be to use another word, perhaps 'with':
with:
<setup code>
while <condition>:
<loop body>
and perhaps:
with:
<setup code>
do:
<loop body>
while <condition>
I also liked the posttest suggestion, as it keeps the loop condition on
top and clearly indicates the behavior of the loop. Though, in the
interest of completeness, I would suggest an optional, default 'pretest'
keyword as well. So we would have:
with:
<setup code>
posttest while <condition>:
<loop body>
I tend to agree with most of the other posters in that this possibly
adds nice but probably unnecessary syntax and may have indention-flow
implications. Further, 'with' may not be the best word either. However,
I prefer clean, intuitive language constructs where necessary, even if
duplicative of certain uses of other constructs, as I believe it
increases readability and makes the behavior of the code more apparent
and elegant.
Explicitly indicating the setup code of a loop appears worthwhile; I
just don't think 'do' indicates this behavior.
--
Jordan McCoy
(jor...@uts.cc.utexas.edu)
Excellent! Whatever the outcome, this frequent request certainly
deserves a PEP.
[...]
> Syntax
>
> The syntax of the while statement
>
> while_stmt : "while" expression ":" suite
> ["else" ":" suite]
>
> is extended as follows:
>
> while_stmt : ["do" ":" suite]
> "while" expression ":" suite
> ["else" ":" suite]
Consider this code:
do:
foo()
while bar():
snee()
while quux():
fnord()
How many loops is that? According to the syntax above, it's two.
But I think some readers might expect it to be one, like this:
while 1:
foo()
if not bar():
break
snee()
if not quux():
break
fnord()
Of course, if the syntax were extended to allow multiple while
clauses, so that this latter interpretation became correct, then
there would arise the problem of what to do when you *did* want
two loops. You'd have to add a pass statement:
do:
foo()
while bar():
snee()
pass
while quux():
fnord()
(Or "else: pass" or "do: pass" in the same place, for example.)
This is not appealing, so we return to the original, where each do
has exactly one while, and there is possible confusion about the
associations of subsequent whiles.
This confusion can arise because in the proposed syntax, we have a
keyword -- while -- which can occur both to introduce the first
clause of a statement, and to introduce the last clause of a
multiclause statement. No other keyword has this property.
For another example of why this is undesirable: suppose you have a
file open in your text editor and the first line on the screen
starts with while. Is there more to the loop off the top of the
screen? You don't know. Again, no other clause-starting keyword
leaves you in doubt: as things stand now, if, while, for, def, and
class always start statements, and elif, else, except, and finally
always continue them.
This argument suggests that we should use something other than
'while' here. Suppose, for example, that we use 'break if' (and
reverse the meaning of the condition). Then we have
do:
foo()
break if not bar():
snee()
break if not quux():
fnord()
This does away with the ambiguities, and gets us multiple
breakouts pretty much for free.
The reader no doubt anticipates my next step, which is to wonder
why we're introducing a new keyword, 'do'. Why not:
while:
foo()
break if not bar():
snee()
break if not quux():
fnord()
In this version the syntactic sugar is particularly transparent.
I do not see that this is appreciably clearer than the presently
idiomatic form, with if ...: break. The alignment of the breaks
with the while is kind of neat, but imho it's not worth changing
the language.
--
Steven Taschuk stas...@telusplanet.net
"I'm always serious, never more so than when I'm being flippant."
-- _Look to Windward_, Iain M. Banks
This, I presume:
do:
...
yn = getYN("You are now dead...")
while not yn:
if getYN("Would you like..."):
intro()
...
--
Steven Taschuk 7\ 7'Z {&~ .
stas...@telusplanet.net Y r --/hG-
(__/ )_ 1^1`
I have to agree with Alex here: Ick. My expectation on seeing
until foo():
bar()
is that it would be equivalent to
while not foo():
bar()
The proposed out-of-order execution is a recipe for confusion,
imho.
--
Steven Taschuk stas...@telusplanet.net
"Telekinesis would be worth patenting." -- James Gleick
> -----Original Message-----
> From: python-l...@python.org [mailto:python-l...@python.org]
> On Behalf Of Steven Taschuk
> Sent: Saturday, May 03, 2003 10:14 AM
> To: 'Python List'
> Subject: Re: PEP 315: Enhanced While Loop
>
> --
> http://mail.python.org/mailman/listinfo/python-list
Python is broken. Just not in this respect <0.25 wink>
Jp
--
It is practically impossible to teach good programming style to
students that have had prior exposure to BASIC: as potential
programmers they are mentally mutilated beyond hope of
regeneration. -- Dijkstra
--
up 1 day, 18:38, 8 users, load average: 0.05, 0.06, 0.08
I like the clean syntax of this suggestion but I see two problems with it:
1) It doesn't handle the same case that the PEP proposed syntax handles:
until not Poor():
MakeMoney()
SpendMoney()
SpendMoney() would have to check for not Poor() before spending. This is a
dependency that is totally unacceptable.
PEP syntax would work (if I understand it correctly):
do:
MakeMoney()
while not Poor():
SpendMoney()
2) Making anything that Python programmers would "just have to understand" is
not Pythonesque and should be avoided.
The PEP proposed syntax is far too unclear as well, requiring that the Python
programmer "just understand" that both MakeMoney and SpendMoney are executed
each iteration through the loop.
The syntax seems to say that SpendMoney is the only thing executed through
each iteration.
For instance, the question of which comes first, MakeMoney or SpendMoney, in
the loop execution is not clear.
I would vote for no change to the language before adding this confusing syntax
to it or the alternative proposal. If a clean, straightforward syntax can be
created, great. These seem to me to violate the Zen of Python.
Cordially,
Scott
Hmm, that could be. I understood the PEP to say that the while condition was
tested after SpendMoney().
> 2) Making anything that Python programmers would "just have to understand"
> is
> not Pythonesque and should be avoided.
I agree that it should be clear or not implemented. I meant that as
programmers, Python programmers must understand the difference between a
pretest and a posttest.
> I would vote for no change to the language before adding this confusing
> syntax
> to it or the alternative proposal. If a clean, straightforward syntax can
> be
> created, great. These seem to me to violate the Zen of Python.
I agree here also. Even the alternative I brought up is not that special and
I've always been content to use a while loop. In fact, it simplifies things
in a certain sense to know that there is only one open ended loop construct.
> But both of you are getting caught up in the name I chose rather than the
> concept of introducing a single new loop construct that somehow clearly
> indicates that the exit test will be performed after the loop body has
> executed once.
I would argue that the usefulness of such a construct might
be limited. It is nice to have an approach that is
maybe one line shorter but if the price is that you have to introduce
an entirely new syntax I'd pass.
Istvan.
Repeat...until is part of Standard Pascal, but hardly anyone uses
Pascal anymore.
For BASIC, the only flavor I've seen that had a posttest loop
construct (other than conditional GOTO) was QBasic, which had a
DO...LOOP block that allowed all 4 possible combinations of
pretest/posttest and WHILE/UNTIL, so your code could have been written
' option 1: pretest WHILE
' This could also be done by the older WHILE...WEND construct
MakeMoney
DO WHILE Poor()
MakeMoney
LOOP
' option 2: pretest UNTIL
MakeMoney
DO UNTIL NOT Poor()
MakeMoney
LOOP
' option 3: posttest WHILE
DO
MakeMoney
LOOP WHILE Poor()
' option 4: posttest UNTIL
DO
MakeMoney
LOOP UNTIL NOT Poor()
While this was a good syntax for a language that delimited blocks with
pairs of statements (e.g., FOR...NEXT, FUNCTION...END FUNCTION),
unfortunately it wouldn't work well in Python.
Personally, I'm satisfied with
This does not strike me as "natural" in Python. By indenting the code
block as shown, a Python programmer would naturally see two blocks, the
second conditioned by a while statement. The normal logic of a while
would mark it as the loop beginning, not as somewhere in the middle of a
loop.
Even if the indentation were arranged differently, for a programmer
coming from the background of a language with a do ... while (or do ...
until) construct, the spec is not natural. The test would be expected at
the very end of the loop (or would at least be applied at the end of the
loop).
This seems to address a problem that doesn't really exist, and to try to
solve it in a forced manner, with rules that do not work as the rest of
the language does.
The main issue seems not to be the creation of a "do once, then test"
loop, but the elimination of duplicated setup code. That duplication can
happen, once in a great while, but is it really frequent enough, or
serious enough, to drive a syntactic upheaval? There are Pythonic ways
of dealing with the issue, and in the worst case, they include
duplicating the code. What's the big deal? It doesn't happen often and
the existing mechanisms can be used to handle the situation when it
does.
Python doesn't need much sugar to make it go down, and in this case,
it's more a case of syntactic garlic -- great for some, but not for
everyone, and for those who don't use it, it just stinks.
--
rzed
I agree, that's the way I do it. Although I still need to work the bugs out
of my MakeMoney() implementation.
> Personally, I'm satisfied with
>
> while True:
> MakeMoney()
> if not Poor():
> break
> --
> http://mail.python.org/mailman/listinfo/python-list
Putting the loop condition *textually before* the loop body
indicates just the contrary. This is my objection (and, I
believe, Alex's), and it has nothing to do with the keyword.
I must agree with the general concensus on 'do...while'. It's hardly ever
needed, it's unpythonic, it's confusing, and it can be delt with by other
more straightforward methods. The PEP tersely discusses the infinite loop
alternative last, as though it were the ugliest and worst of the
alternatives to 'do' that he listed, when in fact (as Alex Martelli
mentioned), it is by far the clearest and most straightforward alternative,
and even easier to grep than 'do..while', because the indentation is more
natural and the code is executed in order.
(Although I understand that infinite loops seem to be reguarded by many
zelots as the moral equivalent of global variables.)
But just to throw in my two cents, I think the following good suggestion can
be made better:
> The reader no doubt anticipates my next step, which is to wonder
> why we're introducing a new keyword, 'do'. Why not:
>
> while:
> foo()
> break if not bar():
> snee()
> break if not quux():
> fnord()
>
> In this version the syntactic sugar is particularly transparent.
> I do not see that this is appreciably clearer than the presently
> idiomatic form, with if ...: break. The alignment of the breaks
> with the while is kind of neat, but imho it's not worth changing
> the language.
This is very verbose, has a somewhat unnatural indentation (it seems like
'break' is outside the while loop), and retains the negation of the
condition, which can often lead to confusion.
while:
[do:] # Notice that this makes things clearer, but is redundant.
<setup code>
[then] if <condition>: # Same here; 'then' is not strictly needed.
<loop body>
Advantages: the entire loop is in a separate code block, the code is
executed in order, and the condition doesn't have to be negated for the
logic to work, unlike with an infinite while loop.
Disadvantages: it is verbose, and there are *two* new keywords! However,
strictly speaking no keywords need to be added at all, although it is far,
far more understandable when the setup code is explicit. Compare:
while:
<setup code>
if <condition>:
<loop body>
[else: break] # This is implicit...
if <condition>:
<loop body continues>
This does the same thing, although without the indentation of setup code it
is less natural. Also, it's easy for someone who first sees this syntax to
think that a bare 'while:' is the same as 'while True:', although 'while:'
currently raises SyntaxError, and could be easily extended to have the above
meaning.
The biggest disadvantage is that it's not crystal clear that the while loop
will break if <condition> is false, and that subsequent 'if' blocks won't
get executed (this is the big advantage of Steven's syntax, where the break
is made explicit.) If you want every condition in the loop to be tested,
without breaking, you'd need to do:
while:
<setup>
if <condition>:
<loop body>
elif <condition>:
<alternate loop body>
else:
<third alternate loop body>
Frankly, I can't think of any use case for this, but you get it for free.
Now that I've whet your appetite, look at this:
while True:
<setup>
if <condition>:
<loop body>
else: break
if <condition>:
<loop continuation>
elif <condition>:
<alternative loop continuation>
elif:
<third alternative loop continuation>
else: break
The only difference between this *current* syntax and the syntax I proposed
is that this makes explicit what I made implicit. But, as the wise ones say,
"Explicit is better than implicit."[1] Therefore the current syntax is
better than the syntax I proposed. In fact, 'if not <condition>' is simply
a shorthand for 'if <condition>: ... else: break'!
So you see, 'do..while' is essentially an infinite loop anyway! Why hide
it? Why shroud our denial of the plain fact of an infinite loop behind this
cryptic syntax? Rise up, my friends! Wallow in the darkness of denial no
more! Embrace the infinite loop! May all your loops be infinite! 'While
True', 'While True'! Infinite Truth!
(Uh, ahem. Ok, I'm better now. Excuse me.)
[1] Tim Peters, _Zen_of_Python_: http://www.python.org/doc/Humor.html#zen
--
Francis Avila
My main objection to the current idiom is that it does not visually
separate the preparation and processing parts of the loop -- unless
one trains oneself to more readily 'see' the 'if not: break' as a
break between them. The unshorthad version, with at most one more
word, does this by indenting the process part more than the prep.. I
think I will give it a try. In the meanwhile, I am -1 on the PEP.
Terry J. Reedy
IMO, this is the crux of the argument.
do:
something
while test:
something else
looks like two separate things.
The traditional argument here is
try:
something
except:
something else
But there is a major difference. Once something enters the except: clause, it does not go back to the try: clause. The processing is one-way at the same indentation level.
OTOH, with do: while:, the processing loops back to across the indentation level.
The only way I could see the above being pythonic would be if it were of the form (ignoring existing meanings of such code):
do:
something
while test:
something else
From there it's a short step to
do:
something
if test:
something else
to
while True:
something
if test:
something else
to (if desired)
while True:
something
if not test:
break
something else
There are plenty of other arguments against the proposed syntactic structure (ambiguity, etc) but they've been well-argued.
I vote that the BDFL immediately reject this PEP so that we can put this issue to rest once and for all. That *is* why the PEP was created wasn't it ... to be rejected? ;)
Tim Delaney
* PEP was submitted to be rejected
If the Python community rejects the PEP so be it, but I really would
like a statement that works like this.
* "Python ain't broken. Please don't fix it."
Python is not broken. But if Python could not be improved we wouldn't
need PEPs at all.
* "do" is unclear
* do-while in other languages doesn't have 2nd suite
* do-while-while ambiguity
* unseen "do" changes the meaning of seen "while"
These are problems which I had not considered when writing the PEP. It
seems to me that the best way to solve them is to choose different
keywords. How about:
perform:
<setup code>
whilst <condition>:
<loop body>
:)
* indentation should indicate execution path
* it's not clear that both blocks execute each iteration
These are good points. There is no precedent in Python for two
indentation groups which are conceptually the same block. Indenting the
while statement to the same level as the rest of the block would solve
this problem but it would hide the loop condition. I prefer the pattern
recommended in the PEP because it clearly indicates the loop condition,
but I do not know for certain that it is better (clearer, more pythonic,
etc).
* a post-test loop is sufficient
The problem I presented in the PEP could not be solved with a post-test
loop. However, please note that a post-test loop could easily be
constructed using the do-while syntax of the PEP.
* infinite loop with break is a well-known idiom in other languages and
is a good way of expressing this behavior
Experienced programmers are used to writing infinite loops and breaking
out of them. However, saying "while True" does not clearly express the
purpose and behavior of the loop. Just because it's traditional to write
infinite loops does not mean that it's a good way to program.
I feel that the use of break is similar to the use of goto in the past.
Goto was necessary because of the limited control structures available
in early languages, but as for, while, if-else, functions, and other
powerful control structures came into use, the goto was no longer
necessary and gradually disappeared. If we adopt loop constructs of
sufficient power and flexibility, the break statement will also no
longer be needed, and will disappear from use.
In other words, if all you have is an infinite loop, everything looks
like it needs one.
If I have not adequately responded to your comment, please re-post it or
send me email.
TTFN
Isaac:
Thanks for the excellently written PEP! There are three minor
changes that I would propose. First, incorporate Alex's
suggestion of "loop" instead of "do" for the introductory
keyword:
loop:
<loop code>
while condition:
<more loop code>
which is (IMHO) quite readable. Secondly, I would suggest
re-ordering the motivation section to stress the particular
existing-syntax-alternative which is most strongly supported
by python experts and PEP opponents. They tend to prefer the
synatx of:
while True:
<loop code>
if not condition: break
<more loop code>
so I would list that alternative first, or perhaps just
indicate in the discussion that it's the syntax preferred by
many in the absense of the PEP. Of course, you should KEEP
the comments about why this solution is not desirable...
after all, this is the MOTIVATION section!
Thirdly, I would suggest that you clearly address the problem
of "dangling while" and specify how it is to be addressed.
Give a specific example like this:
count1 = count2 = 3
loop:
print "A"
while cond1:
cond1 -= 1
print "B"
while cond2:
cond2 -= 1
print "C"
and tell what the output would be. (My proposal would be
"ABABABACCC", but go with whatever solution you like so
long as it's unambiguous.)
Lastly, I would suggest that you _define_ the behavior of
the new construct in terms of existing syntax. Guido likes
that... in fact, in the case of list comprehensions he left
what I would consider a wart (leaving the loop variable
around after completing the comprehension) in order to
exactly conform to the definition he had used). I would
suggest something like this:
The behavior of this construct:
>>> loop:
... <suite 1>
... while <condition>:
... <suite 2>
will be exactly the same as the behavior of
>>> while True:
>>> <suite 1>
>>> if not <condition>: break
>>> <suite 2>
but you'll have to be very careful about handling all
situations including "else" clauses... so I'd probably
add that:
The behavior when an "else" clause is present:
>>> loop:
... <suite 1>
... while <condition>:
... <suite 2>
... else:
... <suite 3>
will be exactly the same as the behavior of
>>> __normal_loop_exit__ = False
>>> while True:
... <suite 1>
... if not <condition>:
... __normal_loop_exit = True
... break
... <suite 2>
>>> if __normal_loop_exit__:
... <suite 3>
>>> del __normal_loop_exit__
*except* for the fact that the variable
"__normal_loop_exit__" will not be visible in any
scope.
Kinda excessive detail for a behavior that's obvious, but
the PEP should spell it out.
Anyway, nice work on this PEP... it's something we've needed
for a long time.
Now for the bad news. I'm -1 on this PEP. I think it should
be rejected, for two reasons: I think the alternative *IS*
sufficiently readable (reasonable people could disagree, but
that's my opinion) and I find newbies tend to write better
code (fewer errors) if they are forced to do their tests at
the top of the loop (which is where the tests belong for the
overwelming majority of loops).
But enough of *MY* reasons... this is a FREQUENT request, and
it deserves a good writeup and evenhanded consideration. If
it's accepted, we'll have a new language feature (and it should
be as well-designed as possible). If it is rejected, at least
what got considered was the very BEST syntax possible.
-- Michael Chermside
Agreed.
> * "do" is unclear
> * do-while in other languages doesn't have 2nd suite
> * do-while-while ambiguity
> * unseen "do" changes the meaning of seen "while"
On the other hand, I proposed essentially the same idea for C back in
1977. Unfortunately, Dennis didn't think it was worth the effort :-)
> These are problems which I had not considered when writing the PEP. It
> seems to me that the best way to solve them is to choose different
> keywords. How about:
> perform:
> <setup code>
> whilst <condition>:
> <loop body>
This is obviously intended to be tongue-in-cheek. However, it does give
me a thought about how to express this notion in a way that is much clearer
and requires no new keywords:
while:
<setup code>
and while <condition>:
<loop body>
Indeed, we can think of this usage as syntactic sugar for the following:
while: ==> while True:
<dedent> and while <condition>: <indent> ==> if not (<condition>): break
By implication, there is no obvious reason that one could not write
while <condition1>:
<code1>
and while <condition2>:
<code2>
and while <condition3>:
<code3>
which would be equivalent to
while <condition1>:
<code1>
if not (<condition2>): break
<code2>
if not (<condition3>): break
<code3>
Looking at these examples, I find myself liking the "and while" idea more,
because it uses (negative) indentation to mark the possible exit points.
--
Andrew Koenig, a...@research.att.com, http://www.research.att.com/info/ark
But C does allow assignment inside expressions, three-way conditionals
and comma as "evaluate both, return right". Together they cover most of
what people might want the "setup" part for.
But adding such features to Python expressions will be quite unpythonic.
> > perform:
> > <setup code>
> > whilst <condition>:
> > <loop body>
>
> This is obviously intended to be tongue-in-cheek. However, it does give
> me a thought about how to express this notion in a way that is much clearer
> and requires no new keywords:
>
> while:
> <setup code>
> and while <condition>:
> <loop body>
Nice. No new keywords. Cannot be easily confused with a C do/while loop.
This probably improves BDFL acceptance factor from -10 to -7 or better!
;-)
Oren
Lovely. Best syntax I've seen so far.
> Indeed, we can think of this usage as syntactic sugar for the following:
>
> while: ==> while True:
>
> <dedent> and while <condition>: <indent> ==> if not (<condition>):
> break
OK. Makes the semantic of an else clause somewhat peculiar (the else
clause's body executes if the condition on the FIRST while causes the
exist, but not if the loop exists because of the condition on any of
the FOLLOWING while's) but perhaps that's secondary.
> By implication, there is no obvious reason that one could not write
>
> while <condition1>:
> <code1>
> and while <condition2>:
> <code2>
> and while <condition3>:
> <code3>
Yes, this generality would help.
> which would be equivalent to
>
> while <condition1>:
> <code1>
> if not (<condition2>): break
> <code2>
> if not (<condition3>): break
> <code3>
>
> Looking at these examples, I find myself liking the "and while" idea more,
> because it uses (negative) indentation to mark the possible exit points.
I do agree the outdents make the structure clearer -- indeed, that's
essentially THE point. I think this proposal should go in the PEP --
it does not suffer disadvantages such as new keyword introduction.
Alex
Oren> But C does allow assignment inside expressions, three-way conditionals
Oren> and comma as "evaluate both, return right". Together they cover most of
Oren> what people might want the "setup" part for.
Yes.
Oren> But adding such features to Python expressions will be quite unpythonic.
Let's not talk about PEP308, OK?
>> while:
>> <setup code>
>> and while <condition>:
>> <loop body>
Oren> Nice. No new keywords. Cannot be easily confused with a C do/while loop.
Oren> This probably improves BDFL acceptance factor from -10 to -7 or better!
That's my guess too.
I must confess that I find this issue less important now that we have
generators. Before that, I was looking for a clean way of writing
while True:
line = infile.read()
if not line:
break
<process a line>
but with generators it is possible to write
for line in infile:
<process a line>
(Yes, I know that you don't need generators to allow such usages for
built-in types, but generators make it much easier to do similar things
with user-defined types)
Andrew Koenig wrote:
> By implication, there is no obvious reason that one could not write
>
> while <condition1>:
> <code1>
> and while <condition2>:
> <code2>
> and while <condition3>:
> <code3>
>
[snip]
>
> Looking at these examples, I find myself liking the "and while" idea more,
> because it uses (negative) indentation to mark the possible exit points.
This on the other hand seems to express the intent a lot better. Great
idea Andrew! FWIW, I'm +1 on this.
Regards,
Dirk Gerrits
Your use of the word "unpythonic" is particularly baffling in this context.
I'm not sure what the official definition of "pythonic" is, but it would
seem that "pythonic" is how one might go about doing things in Python
(the one obvious way to do it, of course). The very nature of a PEP is to
redefine the Python language in some way, and therefore, redefine "pythonic"
and "unpythonic" as well.
To condemn a change in a change in a language because it would result in a
usage different from how the language is currently used is just circular
logic. Not picking a fight, just an observation. ;)
Dave
In case it might help, this is from PEP 1:
'''
Finally, a proposed enhancement must be "pythonic" in order to be accepted
by the BDFL. (However, "pythonic" is an imprecise term; it may be defined
as whatever is acceptable to the BDFL. This logic is intentionally
circular.)
'''
--
Daniel Fackrell (newsgrou...@dfackrell.mailshell.com)
When we attempt the impossible, we can experience true growth.
To me, this is the best alternative (to the current idiom) so far. No
new keyword, no ambiguity about where block begins and ends. However,
the actual execution flow is still not necessarily clear. Reading
this naively, I would expect the loop to continue, and <code1> to
continue to be executed, until <condition1> was false. Or something
like that.
> which would be equivalent to
>
> while <condition1>:
> <code1>
> if not (<condition2>): break
> <code2>
> if not (<condition3>): break
> <code3>
>
> Looking at these examples, I find myself liking the "and while" idea
more,
> because it uses (negative) indentation to mark the possible exit
points.
I am beginning to like explicit breaks more.
Terry J. Reedy
It was clear to me that you would like acceptance. However, a
rejected PEP that lists several alternatives to the status quo and
their pros and cons will be a service to the community.
...
> I feel that the use of break is similar to the use of goto in the
past.
'Break' and 'continue' are recognized in language design theory as
restricted gotos, as is 'raise x' (or longjump() in C) . They are
practical compromises with structured purity.
Terry J. Reedy
- if condition1 is true but condition2 is false is code1 repeated?
- what if condition2 is true but condition1 is false?
- is there any meaning for "or while"?
- if condition1 and condition2 are both true do both code1 and code2 get
repeated together, or is nesting implied (does code2 repeat until
condition2 is false then you start with code1 again?)?
these aren't necessaril criticisms - maybe i'd ask similar things about
existing constructs if they were new to me. but it doesn't seem totally
obvious what the answers are (i'm guessing the answers are: yes, nothing,
no, together, but i'm not 100% sure on any of them)
andrew
Dirk Gerrits said:
> I already expessed that I like the general idea of the proposed
> construct. But I agree with others that the proposed syntax is not too
> clear.
>
> Andrew Koenig wrote:
>> By implication, there is no obvious reason that one could not write
>>
>> while <condition1>:
>> <code1>
>> and while <condition2>:
>> <code2>
>> and while <condition3>:
>> <code3>
>>
> [snip]
>>
>> Looking at these examples, I find myself liking the "and while" idea
>> more,
>> because it uses (negative) indentation to mark the possible exit points.
>
> This on the other hand seems to express the intent a lot better. Great
> idea Andrew! FWIW, I'm +1 on this.
>
> Regards,
> Dirk Gerrits
>
>
>
Now, *this* is why we have PEPs! Without them, everything old is new
again, every few years.
See Guido's reaction:
See the implementation announcement:
http://groups.google.com/groups?q=g:thl3737064544d&selm=7hsv80%24g9j%241%40news.tamu.edu
I can't for the life of me remember how it died, though.
wow-it's-been-four-years-ly yrs,
Evan @ 4-am
Well, maybe. I hadn't thought of else clauses. Indeed, that may be
another reason for my proposed syntax, because I would certainly want
the else to execute if the condition of *ANY* of the while clauses
causes the exit (but not if a break causes it).
Evan> Now, *this* is why we have PEPs! Without them, everything old is new
Evan> again, every few years.
Evan> See Guido's reaction:
Evan> See the implementation announcement:
Evan> http://groups.google.com/groups?q=g:thl3737064544d&selm=7hsv80%24g9j%241%40news.tamu.edu
Evan> I can't for the life of me remember how it died, though.
Evan> wow-it's-been-four-years-ly yrs,
That's hilarious! I had nothing at all to do with Python in 1999, which means
that I came up with the same idea completely independently.
And Guido liked it too! What are we waiting for? :-)
While I agree that this syntax is an improvement over the original PEP
version, it still would create a block structure different from any
other in Python.
Andrew says that this:
> while <condition1>:
> <code1>
> and while <condition2>:
> <code2>
> and while <condition3>:
> <code3>
would be equivalent to this:
>
> while <condition1>:
> <code1>
> if not (<condition2>): break
> <code2>
> if not (<condition3>): break
> <code3>
>
... which means that the first 'while' and the second do not mean the
same thing. That's less than "obvious" (ergo, less than "Pythonic"?).
If "while" does not imply a looping construct, why use the word?
How about:
while <condition1>:
<code1>
and if <condition2>:
<code2>
and if <condition3>:
<code3>
Now the if tests do not imply loops within loops, and because they are
anded (in some vague way), the failure of any of them would break out
of the while loop.
I'd still prefer to see an indention of the entire while block,
though -- it seems more obvious:
while <condition1>:
<code1>
and if <condition2>:
<code2>
and if <condition3>:
<code3>
... or maybe not.
--
rzed
while <condition1>:
<code1>
and while <condition2>:
<code2>
and while <condition3>:
<code3>
My preference is to define the loop as all of the code blocks together,
and treat all the while clauses symmetrically. My original proposal only
allowed one while clause, but I see no particular reason to keep to that
limit. Any CS people know of a reason why multiple loop conditions would
be a bad thing?
andrew cooke wrote:
> - if condition1 is true but condition2 is false is code1 repeated?
No. The loop will exit after finding condition2 to be false.
> - what if condition2 is true but condition1 is false?
The loop will exit after finding condition1 to be false.
> - is there any meaning for "or while"?
The use of "and" is motivated by a desire to not introduce new keywords
into the language. There is no proposed meaning for "or while".
> - if condition1 and condition2 are both true do both code1 and code2 get
> repeated together, or is nesting implied (does code2 repeat until
> condition2 is false then you start with code1 again?)?
No nesting is implied. The loop repeats as long as it finds all
conditions to be true when they are evaluated. The first one found to be
false causes the entire loop to exit, transferring control to the else
clause, if present.
> these aren't necessaril criticisms - maybe i'd ask similar things about
> existing constructs if they were new to me. but it doesn't seem totally
> obvious what the answers are (i'm guessing the answers are: yes, nothing,
> no, together, but i'm not 100% sure on any of them)
Fair enough. Since this construct is not a typical one found in other
languages, no one is expected to immediately know what it does at first
glance. However, I believe that the "and while" syntax is easy enough to
recognize and remember that once people learn its semantics there won't
be any confusion.
TTFN
Yes. That is one of the fundamental ideas that I'm shooting for. The
loop condition needs to be clearly visible so the loop's behavior is
clearly understood.
As long as the syntax makes the loop clear the exact spelling doesn't
matter much. I like the "and while" syntax well enough, and it seems to
be an acceptable compromise between clarity and not breaking compatibility.
The only thing that concerns me about the generalized case
while <cond1>:
<block1>
and while <cond2>:
<block2>
is that it has the same problem as was brought up about the do-while
syntax: When a part of the loop is off the screen or on another page,
you might get the wrong idea about the loop. However, if you see
"while:" you know something funny is going on and you can pay closer
attention.
TTFN
Substituting Alex Martelli's definition of Pythonic in that sentence gives
us: "...a proposed enhancement must be of, relating to, or resembling
Python...". This is hopelessly circular, to the point where you can draw no
useful conclusion from that requirement. Even if you acknowledge the
circularity from day (or PEP) one.
Erik Max Francis's definition was a bit easier to incorporate: "...a
proposed enhancement must seem to follow good style laid about by the
language Python...".
So, I guess it all depends on what the word means to you (or to the BDFL,
really). Not to mention your definitions of "good" and "style".
Cheers,
Dave
No more than you could with the current way of spelling it:
while <cond1>:
<block1>
if not <cond2>:break
<block2>
if you're scrolled so the END of the while's body is not showing, then
you know there MIGHT be exist conditions further down -- nothing new.
The issue with the original proposal's "do ... while cond>" is that you
might have been looking right at the "while cond:" clause AND have no
way to now you should be looking BACKWARDS for a crucial part of the
loop -- THAT would have been a novel trap. But there is nothing like
that in this proposal.
Alex
Good! (Then the process is working.)
[...]
> * infinite loop with break is a well-known idiom in other languages and
> is a good way of expressing this behavior
>
> Experienced programmers are used to writing infinite loops and breaking
> out of them. However, saying "while True" does not clearly express the
> purpose and behavior of the loop. Just because it's traditional to write
> infinite loops does not mean that it's a good way to program.
Of course, with 'while True' and 'if ...: break', usually the loop
is not infinite (barring bugs). If I understand correctly, you're
saying that 'while True' suggests that the programmer *intends* an
infinite loop, and so is misleading.
If that's right, how about this?
loop:
do some stuff
if should stop now:
break
do some other stuff
The 'loop' just says "this is a loop; execution comes back here at
the end of the block". Unlike 'while True', it does not also
explicitly say "we will continue looping as long as True is true".
(The notion is that the problem is while's mandatory condition,
which adds no information in the case of these so-called infinite
loops.)
Any better in your view? (I can't tell; I'm too used to looking
for 'if ...: break' after seeing 'while True'.)
> I feel that the use of break is similar to the use of goto in the past.
> Goto was necessary because of the limited control structures available
> in early languages, but as for, while, if-else, functions, and other
> powerful control structures came into use, the goto was no longer
> necessary and gradually disappeared. If we adopt loop constructs of
> sufficient power and flexibility, the break statement will also no
> longer be needed, and will disappear from use.
Imho 'break' and 'continue' together make 'while' a "loop
construct of sufficient power and flexibility". :)
Incidentally, I'd like to see a concrete example of the kind of
problem which you'd solve by writing a loop with the proposed
syntax. (Most such cases in my experience are problems involving
a stream of objects to be processed; it would be nice to see
either a different kind of problem for which this syntax is
suited, or a stream-of-objects problem for which it is superior to
approaches using, say, iterators and a for loop.)
[...]
--
Steven Taschuk stas...@telusplanet.net
"[T]rue greatness is when your name is like ampere, watt, and fourier
-- when it's spelled with a lower case letter." -- R.W. Hamming
> This is obviously intended to be tongue-in-cheek. However, it does give
> me a thought about how to express this notion in a way that is much clearer
> and requires no new keywords:
>
> while:
> <setup code>
> and while <condition>:
> <loop body>
[etc]
This is very elegant. It's a pity that it doesn't work well
for the special case of a "do...while" loop, though.
--
Gareth McCaughan Gareth.M...@pobox.com
.sig under construc
Gareth> This is very elegant. It's a pity that it doesn't work well
Gareth> for the special case of a "do...while" loop, though.
while:
<loop body>
and while <condition>:
pass
Yes, of course. That's what I meant by "doesn't work well
with". I'm sorry if that wasn't clear.
> By implication, there is no obvious reason that one could not write
>
> while <condition1>:
> <code1>
> and while <condition2>:
> <code2>
> and while <condition3>:
> <code3>
> ...
>
> Looking at these examples, I find myself liking the "and while" idea more,
> because it uses (negative) indentation to mark the possible exit points.
Allowing break expressions to dedent would help clarify the current
idiom:
while <condition1>:
<code1>
break if <condition2>:
<code2>
Or to make the colon scan better:
while <condition1>:
<code1>
break if <condition2> else:
<code2>
Neil
As I understand the proposal, this is computationally equivalent to
and only marginally different in form from the currently legal
while <condition1>:
<code1>
if <condition2>:
<code2>
if <condition3>:
<code3>
else: break
else: break
So the proposals seem to be about changing indentation and making
break implicit instead of explicit. This is at most an esthetic and
not a functional enhancement.
I am currently thinking that Python's syntax should be 'congealed' --
not quite frozen but far from liquid -- and (with at most a few
exceptions) only changed (at least for 2.x series) for reasons other
than the syntax change itself. Examples are any remaining changes
needed to finish unify ints and longs or types and classes.
Terry J. Reedy
It was suggested to me that the colon might be left off for a statement
that does not begin a block, like so:
while:
<loop body>
and while <condition>
It remains to be seen whether the small difference of a missing colon is
enough to remind people that the block is not present.
TTFN
I'd be more inclined to go with:
while:
<loop body>
and while <condition>:
continue
...just for the way it sounds when read aloud.
Cheers,
Evan @ 4-am
This would remove my objection to the fact that the condition is outdented, since it provides an obvious indication (and) that it's a continuation of an existing structure.
Hmm ... how does it look without outdenting?
while [<condition1>]:
<code1>
and while <condition2>:
<code2>
and while <condition3>:
<code3>
I think I prefer it with the outdents.
Tim Delaney
Tim> while [<condition1>]:
Tim> <code1>
Tim> and while <condition2>:
Tim> <code2>
Tim> and while <condition3>:
Tim> <code3>
Tim> I think I prefer it with the outdents.
Me too.
I like the idea, but not the choice of keywords. I
would prefer to see
while:
<setup code>
gives <condition>:
<loop body>
--
Greg Ewing, Computer Science Dept,
University of Canterbury,
Christchurch, New Zealand
http://www.cosc.canterbury.ac.nz/~greg
Out of curiousity, supposing that the "while and while ..." syntax were
accepted, are we going to start seeing requests for continue statements that
can continue at any while? It wouldn't terribly surprise me, and my gut
feel tell me that following that path would be a Bad Thing(tm).
what this keyword does is introduce a logical level of grouping (i.e.,
the code underneath it is indented once.) It is strictly equivalent to
"if True:"
Whether this would be worthwhile or not, I don't know, but it seems both
simple and sufficient to satisfy what I understand of your request.
I.e., it would allow one to write
do:
""" some code """
while(test):
""" some more code """
Unfortunately, I can think of many variations on this that would be
equally valuable, e.g., one that only executes once, or only executes
when a control variable == None, or one that locks access when another
thread is using it or...
And with so many similar plausibilities, probably none of them are
really appropriate (though that sync method has arguments, Java has
something like that).
--
-- Charles Hixson
Gnu software that is free,
The best is yet to be.
Agreed. However, I can't imagine when such a control structure would
be useful. Perhaps I'm biased, because I almost never use continue
statements, but if I am, you should nave no difficulty finding
an example for us :-)
> PEP: 315
> Title: Enhanced While Loop
> Version: $Revision: 1.1 $
> Last-Modified: $Date: 2003/05/02 22:53:32 $
> Author: W Isaac Carroll <icar...@pobox.com>
> Status: Draft
> Type: Standards Track
> Content-Type: text/plain
> Created: 25-Apr-2003
> Python-Version: 2.4
> Post-History:
>
> Abstract
>
> This PEP proposes adding an optional "do" clause to the beginning
> of the while loop to make loop code clearer and reduce errors
> caused by code duplication.
Lukewarm. The while True: ... if condition: break ... is so widespread
and understandable that I don't see any huge benefit from the
introduction of a new construct for handling it, but at the same time
wouldn't be strongly opposed to one being added to the language.
The other variants which involve a
KEYWORD condition:
statements
where it's just "understood" that the statements will be executed once
regardless seems like a very bad precedent, since it's quite nonobvious
that that's the case, and I can't imagine a reasonable keyword used
there that would flag that behavior in an intuitive way.
--
Erik Max Francis / m...@alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, USA / 37 20 N 121 53 W / &tSftDotIotE
/ \ To be adult is to be alone.
\__/ Jean Rostand
CatCam / http://www.catcam.com/
What do your pets do all day while you're at work? Find out.
> I have to agree with Alex here: Ick. My expectation on seeing
> until foo():
> bar()
> is that it would be equivalent to
> while not foo():
> bar()
> The proposed out-of-order execution is a recipe for confusion,
> imho.
Agreed. There is precedent for such an "until" construct (i.e., one
that simply a while with a negated conditional) in other languages, such
as Perl. So not only would such a construct be nonobvious, there is
directly conflict with what it would mean in other languages. Giving
false indicators of intuitiveness is a really, really bad idea.
(And no, I don't think a Perl-like "until" should be added, either.)
> Perhaps this should be done in a more general way. Just create a block
> keyword, do: is fine.
>
> what this keyword does is introduce a logical level of grouping (i.e.,
> the code underneath it is indented once.) It is strictly equivalent to
> "if True:"
>
> Whether this would be worthwhile or not, I don't know, but it seems both
> simple and sufficient to satisfy what I understand of your request.
> I.e., it would allow one to write
> do:
> """ some code """
> while(test):
> """ some more code """
It would allow you to write that, but it wouldn't
mean what WIC wants it to. In his proposal, the
loop body contains both suites; in yours, it contains
only the second.
I think my biggest problem with the PEP and the modified versions which are
following it on this thread is that the whole idea addressed a very small
set of real-world use cases, and that it would likely set a bad precedent
which could allow a figurative avalanche of flow-control structures that are
begging to be added to the language.
Just to illustrate based on the idea presently before us, we have in the
language already:
while <cond>:
<statements>
This proposal would add some variation to allow setup code to be executed as
part of the loop, but before the <cond>, which is argued as a convenient way
of handling setup code (I've picked my favorite of the variations):
while <optionalCond>:
<statements>
and while <cond>:
<statements>
If we let this in, might we soon see a request to allow a portion of the
loop to execute once after the <cond> tests false for the purpose of
allowing some sort of cleanup to occur that might run a risk of duplicating
code?
And let's not neglect the fact that some other languages have negative logic
versions of their flow-control statements, so if pressure continued long
enough, we might (shudder) see new keywords added to eliminate the need for
a "not".
After typing this, I'm starting to feel that maybe this is just an
unimportant, meaningless tangent. I sure hope so.
while <condition1>:
<code1>
break unless <condition2>
<code2>
break unless <condition3>
<code3>
Too Perlish?-) But it does read rather good, in my humble opinion.
Even "break if not <condition>" could be a small readability improvement,
the eye ought to see the "break" word easier. Since list comprehensions
have an optional if part, why can't break?
>I'd still prefer to see an indention of the entire while block,
>though -- it seems more obvious:
>
>while <condition1>:
> <code1>
> and if <condition2>:
> <code2>
> and if <condition3>:
> <code3>
Not that much difference between it and the standard
"if not condition2: break" code.
Marcus
I think so, too.
I wish Python kept clean without overdone constructs... I think it
is better only to add an intuitive keyword "loop" which is equivalent
to "while True" (like several other languages) if we need to fix the
language.
And from the mathematical view, "while...else..." is cleanly
defined. Let W be "while e: s else: t".
Then W is the least fixed point of the equation:
W = if e:
s; W
else:
t
Imho, both constructs of W. I. Carroll and A. Koenig lack
such simplicity.
-- SUZUKI Hisao
Marcus> Too Perlish?-) But it does read rather good, in my humble opinion.
I think I disagree. The point is that the multiple exits should be
considered normal exits, not abnormal ones. The difference appears
when you add an "else" clause:
while:
line = infile.getline()
and while line:
<process the line>
if <something is wrong>: break
else:
<code to execute after normal exit>
If the loop terminates normally -- that is, because we reached the end
of the file -- I would like the code after "else:" to execute. If,
on the other hand, it terminates because of the break, I would like the
code after "else:" not to execute.
I think this behavior is analogous to the current usage:
for line in infile:
<process the line>
if <something is wrong>: break
else:
<code to execute after normal exit>
I'm sure someone will correct me if I'm wrong :-)
> And from the mathematical view, "while...else..." is cleanly
> defined. Let W be "while e: s else: t".
> Then W is the least fixed point of the equation:
> W = if e:
> s; W
> else:
> t
>
> Imho, both constructs of W. I. Carroll and A. Koenig lack
> such simplicity.
while C1:
S1
and while C2:
S2
else:
E
is the least fixed point of
W1 == if C1: { S1; W2 }
else: E
W2 == if C2: { S2; W1 }
else: E
But I'm not sure why this is important, since (1) neither
of these deals with "break" and "continue" and (2) maybe
0.001% of Python programmers think of their programs as
built out of least fixed points of sets of equations.
It's actually about 43%. However, in the spirit of newbie-friendly
egalitarianism, most of them aren't gauche enough to mention it.
you-can't-spell-python-without-the-y-combinator-ly y'rs - tim
> > [W Isaac Carroll posted PEP 315 (revision 1.1)]
>
> Isaac:
>
> Thanks for the excellently written PEP! There are three minor
> changes that I would propose. First, incorporate Alex's
> suggestion of "loop" instead of "do" for the introductory
> keyword:
>
> loop:
> <loop code>
> while condition:
> <more loop code>
>
I agree that ``loop:`` is better than ``while 1:`` and ``while True:``
(I must admit that while I like `True`/`False`, I still prefer the
``1`` since a number visually stands out better and it looks more
"syntetic"). However I'd perhaps prefer ``while:`` over ``loop:`` for
the ``and while`` proposals. Make clear that this part of the PEP is
optional.
> which is (IMHO) quite readable. Secondly, I would suggest
> re-ordering the motivation section to stress the particular
> existing-syntax-alternative which is most strongly supported
> by python experts and PEP opponents. They tend to prefer the
> synatx of:
>
> while True:
> <loop code>
> if not condition: break
> <more loop code>
>
> so I would list that alternative first, or perhaps just
> indicate in the discussion that it's the syntax preferred by
> many in the absense of the PEP. Of course, you should KEEP
> the comments about why this solution is not desirable...
> after all, this is the MOTIVATION section!
>
Agreed. Moreover, you should call the construct by its known name -
"loop-and-a-half". AFAIK, this construct was first published in
Knuth's excellent "Structural programming with GOTO" paper (google for
it) and there he invented this name.
> Thirdly, I would suggest that you clearly address the problem
> of "dangling while" and specify how it is to be addressed.
This is fixed in the ``and while`` idea. I'd like to suggest a few
variants. First, the "ideal" indentation would be::
loop:
<suite>
<cond>:
<suite>
This is very alien to python's indentation style so it'd not work.
Somebody said ``and while`` sounds wrong because it seems to split it
into several loops, suggesting ``and if``. I'd like to propose a bare
``and``::
while:
<suite>
and <cond>:
<suite>
This reads stangely if the first while has no condition, so perhaps
even the ``and`` should be omitted (*Parsing danger*, Will Robinson).
As a radical option, consider this::
while
<suite>
<cond>:
<suite>
This reads nicely as "a while whose condition was moved into the
middle of the loop :-). Yes, I know Guido will not accept this.
> Lastly, I would suggest that you _define_ the behavior of
> the new construct in terms of existing syntax. Guido likes
> that...
Basically good idea.
>[snip]
> but you'll have to be very careful about handling all
> situations including "else" clauses... so I'd probably
> add that:
>
> The behavior when an "else" clause is present:
> [snip]
> will be exactly the same as the behavior of
>
> >>> __normal_loop_exit__ = False
> >>> while True:
> ... <suite 1>
> ... if not <condition>:
> ... __normal_loop_exit = True
> ... break
> ... <suite 2>
> >>> if __normal_loop_exit__:
> ... <suite 3>
> >>> del __normal_loop_exit__
>
> *except* for the fact that the variable
> "__normal_loop_exit__" will not be visible in any
> scope.
>
If *that's* how you'll define it, I think it's a bad idea. At this
stage, IMHO it's best to just give the whole new definition of
``while``.
> Anyway, nice work on this PEP... it's something we've needed
> for a long time.
>
Seconded.
> Now for the bad news. I'm -1 on this PEP. I think it should
> be rejected, for two reasons: I think the alternative *IS*
> sufficiently readable (reasonable people could disagree, but
> that's my opinion) and I find newbies tend to write better
> code (fewer errors) if they are forced to do their tests at
> the top of the loop (which is where the tests belong for the
> overwelming majority of loops).
>
> But enough of *MY* reasons... this is a FREQUENT request, and
> it deserves a good writeup and evenhanded consideration. If
> it's accepted, we'll have a new language feature (and it should
> be as well-designed as possible). If it is rejected, at least
> what got considered was the very BEST syntax possible.
>
There is a trivial test that nobody seems to have done yet:
$ cd Python-2.3b1/Lib
$ find -name '*.py' | xargs cat | grep -c $'^[ \t]*while .*:'
730
$ find -name '*.py' | xargs cat | grep -c $'^[ \t]*while 1:'
220
$ find -name '*.py' | xargs cat | grep -c $'^[ \t]*while True:'
50
WOW! That means that about *every third* while loop in the standard
library is an "infinite" loop! I'm sure each of them has a break. I
can't easily check how many have simple post-conditions ("do until")
but in my experience, checking at the end is less useful than at the
middle. These statistics convince me that this PEP is definitely not
YAGNI.
The other notable thing is that there are only ~730 while loops in the
whole standard library (a little more, the ``.*:`` misses multi-line
conditions). The simple truth is that ``for`` is just much more
useful:
$ find -name '*.py' | xargs cat | grep -c $'^[ \t]*for .* in .*:'
2683
As expected ;-)
--
Beni Cherniavsky <cb...@users.sf.net>
"Intercept course punched in." -- from a sci-fi movie, happening
centuries from now. So don't forget your puch-card skills yet!
Thus,
W1 == if C1:
S1
if C2:
S2
W1
else:
E
else:
E
> But I'm not sure why this is important, since (1) neither
> of these deals with "break" and "continue" and (2) maybe
> 0.001% of Python programmers think of their programs as
> built out of least fixed points of sets of equations.
Yes, many ones do not think of fixed points, but I hope you
will understand the core point easily. Well, you can see the
equation just a "macro" definition ;-). Frankly speaking,
"least" just means that the interpreter executes only what
written in the given program.
The important point is that you can see the (non-)simplicity
of the given construct from its equation (read 'macro') clearly.
Given the equation, you can now see the secret of the "else"
clause of "while" statement of Python, which seems very
unique :-) It corresponds that of "if" plainly. I believe
the naturalness of the "while..else.." comes from this.
"and while" lacks such simple correspondence and has
multiple occurrences of E (statements in "else" clause).
And you may think of a looping construct which is described
as a recursive "if..elif..". For example,
while C1:
S1
or while C2:
S2
or while C3:
S3
else:
E
whose meaning is given by
W = if C1:
S1; W
elif C2:
S2; W
elif C3:
S3; W
else:
E
Note that it is not my invention. If I remember correctly,
Concurrent Pascal had such a construct.
Though I doubt its actual usefulness, it is so natural
that some may mistake the meaning of "and while" for it ;-)
Thus I want a plain "loop", if we have to fix the looping
constructs of Python.
BTW, as for "break" and "continue", I think there are two
approaches.
A: unfold the equation, and reduce it to "if..else..".
B: use "try..raise..except.." construct.
If I remember correctly, the Modula-3 report takes the
approach B to describe its BREAK statement.
-- SUZUKI Hisao