[Python-ideas] Updating PEP 315: do-while loops

Raymond Hettinger python at rcn.com
Sun Apr 26 03:00:26 CEST 2009

Am working on PEP 315 again, simplifying the proposal by focusing on a more standard do-while loop.

The two motivating cases are:

1) A pattern of repeated code blocks before and inside a traditional while-loop.  Here's an example from random.sample():

    j = _int(random() * n)
    while j in selected:
        j = _int(random() * n)

2) A pattern of ending a "while True:" loop with an "if not <cond>: break".  Here's an example from random.normalvariate():

    while 1:
        u1 = random()
        u2 = 1.0 - random()
        z = NV_MAGICCONST*(u1-0.5)/u2
        zz = z*z/4.0
        if zz <= -_log(u2):

The challenge has been finding a syntax that fits well with the patterns in the rest of the language.
It seems that every approach has it's own strengths and weaknesses.

1) One approach uses the standard do-while name but keeps usual python style formatting 
by putting the condition at the top instead of the bottom where it is in C and Java:

    do ... while j in selected:
        j = _int(random() * n)

    do ... while zz > -_log(u2):
        u1 = random()
        u2 = 1.0 - random()
        z = NV_MAGICCONST*(u1-0.5)/u2
        zz = z*z/4.0

This syntax uses the ellipsis for an additional mental cue reminding the reader that the
enclosed code block is executed before the condition is evaluated.  It is not unlike
the with-statement which has both enter and exit behaviors signaled by a single leading
keyword and an indented block.  Also, code-at-the-top approach fits well with 
the way the compiler would generate code with the condition test being 
preceding the loop body:

    0   SETUP_LOOP             30 (to 33)
    3   JUMP_ABSOLUTE          18
    6   LOAD_NAME               0 (x)
    9   LOAD_NAME               1 (y) 
    12  COMPARE_OP              0 (<)
    15  POP_JUMP_IF_FALSE     33
    18      <loop body>
    30  JUMP_ABSOLUTE           6
    33  LOAD_CONST               1 (None)

I like the ellipsis form because of the mental cue it provides, but the proposal still 
works with any other spelling variant:

    do_while <cond>:
    do while <cond>:
    do_body_first_and_then_loop_if_the_test_condition_is_true <cond>:

2) Another approach is to put the test at the end.  Something like:

        j = _int(random() * n)
    :while j in selected

        j = _int(random() * n)
        while j in selected

These seem syntactically weird to me and feel more like typos than real python code.
I'm sure there are many ways to spell the last line, but in the two years since I first worked
on the PEP, I haven't found any condition-at-the-end syntax that FeelsRight(tm).

Probably everyone has an opinion on these, but I don't any think those could be called 
bike-shedding.  The spelling does matter and hopefully the cleanest solution can be found.
It would be really great if we were to get some decent spelling of do-while in the language.


P.S.  I've punted on the more complex PEP-315 variants with repeated setup code:

    <setup code>
    while <condition>:
        <loop body>
        <setup code>

It was hard enough to get a decent spelling for do-while.

Also, I've punted on the while-cond-with-assignment case that is being handled by
other proposals such as:

    while f.read(20) as data != '':

More information about the Python-ideas mailing list