Thoughts on PEP315

Stephen Horne $$$$$$$$$$$$$$$$$ at $$$$$$$$$$$$$$$$$$$$.co.uk
Mon Sep 22 20:47:03 EDT 2003


PEP315 (Enhanced while loop) suggests a syntax as follows...

  do:
    ...
  while condition:
    ...

The motives are IMO good, but I don't like this solution. It
replicates a problem with the C do loop (even though this is actually
different to the C do loop).

Imagine that you can see the following in a piece of code...

    statements1

  while condition :

    statements2

The question is this - is this a new old-style while loop starting at
this point, or is it the 'while' part of a new-style while loop? Given
the truncated view typical of a single screenful of code, this could
be far from clear. 'statements1' could follow after an earlier 'do:',
but it could equally follow after an earlier 'if ... :' or 'while ...
:' or whatever.

This is a situation where anyone who is unaware of the new 'do:' part
(or who simply didn't think about it) could end up being confused by
the 'while ... :' line.

This is not an unusual situation when the C 'do' loop is used, simply
because that loop is quite rarely used in practice - people don't
expect it, so when people see...

    statements
  }
  while (condition);

the tendency is to assume that either the semicolon is a mistake, or
the while line is a conventional while loop with no body (not unusual
in C code if the condition has side-effects).

There are other issues. For example...

  do :
    ...
  while c1 :
    ...
  while c2 :
    ...

Is the second 'while' line the start of a new loop, or is it a
continuation of the first loop (a second exit point)? If it is a
continuation, do you really potentially need to use a 'pass' to
prepare for a second loop...

  do :
    ...
  while c1 :
    ...

  pass  #  to assert that the previous loop is ended

  while c2 :
    ...

I basically think that this is too error-prone.

When faced with a problem inventing new language syntax, IMO the first
thing to do should always be to review other languages for existing
solutions. Why re-invent the wheel? Here, I'll limit myself to
alternate-to-while-loop structures which provide more flexibility than
a basic while loop (so I'm excluding Pascals repeat-until, for
instance, which is slightly different to but no more flexible than the
while loop).


First, ANSI Basic provides a generalised loop which is a bit more
flexible - it allows both a precondition and a postcondition.

  do [while condition]
    ...
  loop [until condition]

This can be useful in some situations, but it doesn't solve the PEP315
issue.

The C for loop deserves a quick mention because it isn't just an
integer for loop. The syntax is

  for (<initialisation>; <precondition>; <'increment'>)
    statement

Because the <initialisation> and <increment> can be any legal C
statements, the loop is quite flexible. Combined with the comma
operator, for instance, it allows 'in-step' loops such as this array
reverser...

  for (i = <first item index>, j = <list item index>; i < j; i++, j--)
  {
    temp = array [i];
    array [i] = array [j];
    array [j] = temp;
  }

Once again, though, this doesn't solve the PEP315 problem.

In terms of flexible loops, Ada is basically the Daddy. The mimimalist
for is...

  loop
    ...
  end loop;

But you can add a 'while' part or a 'for' part to the start...

  while condition loop
    ...
  end loop;

  for i in 1..10 loop
    ...
  end loop;

  for i in reverse 1..10 loop
    ...
  end loop;

And in addition, you can use an 'exit when' line (in any of the cases
above) to give essentially a conditional break...

  loop
    ...
  exit when condition;
    ...
  end loop;

This last form finally handles the PEP315 problem. But Ada goes a
little further. Suppose you have nested loops, and you want to exit
more than just the innermost one? In Ada, you can name the loops and
specify by name which one you want to exit...

  outerloopname: loop
    innerloopname: loop
      ...
    exit innerloopname when condition;
      ...
  exit outerloopname when condition;
      ...
    end loop;
  end loop;

So what might be worth using in Python? I like the idea of an 'exit
when' line, which is basically what the PEP315 'while' line gives, but
I think a different syntax should be used. I would suggest that 'exit'
in the Ada loop means essentially what 'break' means in Python now,
except for the condition. So I would suggest the following as a
possibility...

  while True :
    ...
  break if <condition> :
    ...

This has no new keywords, but should be both clear and effective. The
parser should expect a semicolon immediately after existing break
keywords, so the distinction should be immediately clear to the Python
parser.

A 'continue if' might be considered as well.

That is sufficient to handle PEP315 with no new keywords and without
the 'is this a new loop?' confusion. Should the need for named loops
ever be considered in Python, there is also an obvious place to put
the name between the 'break' and 'if'.


What about all those other loop ideas, though...

1.  Combining a precondition with a postcondition (ANSI Basic)...

    No problem - just put the 'break if' at the end of the loop. It's
    not an 'until' postcondition, but who cares. If anything, having
    all loop conditions with the same 'sense' is more consistent.

      while True :
        ...
      break if <condition> :

      statements after loop

2.  In-step looping (C for loop)...

    This is just syntactic sugar for a while loop anyway...

      setup1
      setup2

      while condition :
        statement

        increment1
        increment2

    My personal opinion is that there is some need for a more
    convenient iterate-over-integers, but this kind of stuff should
    normally be done as above.

3.  Named loops (Ada)...

    Don't know. It may be a feature without a purpose. In the two
    and a half years when Ada was my main language, I don't remember
    ever using it.

4.  Start-of-loop keyword which doesn't require a condition (Basic,
    Ada)...

    This is matched by the PEP315 'do', but is not actually necessary
    if you use 'break if' for the exit point - you can simply use
    'while True :' to start the loop without ambiguity.

But I admit it - the reason for going through the various languages is
because I'm sick of being accused of trying to change Python into *. I
don't think anyone can reasonably accuse me of trying to change Python
into Basic, C and Ada at the same time (maybe I should find a way to
get Prolog into the mix). Though it is slightly worrying that my
preferred idea was adapted from one particular language. Still,
traditionally I'm accused of trying to change Python into C, C++,
Java, Pascal, Haskell or more recently C# so at least Ada will (if I
remember right) make a change ;-)


-- 
Steve Horne

steve at ninereeds dot fsnet dot co dot uk




More information about the Python-list mailing list