statements in control structures (Re: Conditional Expressions don't solve the problem)

Huaiyu Zhu huaiyu at gauss.almadan.ibm.com
Wed Oct 17 23:22:36 EDT 2001


You raised several valid points, but your picking on the examples sometimes
hinges on specific wart of the examples.  Obviously I did not contruct the
examples well enough in this respect.  So let me give it another try.

>It doesn't have to use an extra variable.
>
>  while 1:
>    x = next()
>    if x.is_end:
>        raise "not found"
>    y = process(x)
>    if y.is_what_we_are_looking_for():
>        break
>

Do you recommend always using this
    
    while 1:
        if not A:
            E
            break
        B
        if C: break
        D
    
in place of this?
    
    while A:
        B
        if C: break
        D
    else:
        E

This style change is orthogonal to the issue of statements before condition.
The question is whether the else-clause in while-loop has any real use.


>>            while x = get_next(); x:
>>               whatever(x)
>
>I prefer the syntax mentioned some months ago when this discussion
>last flared up.
>
>loop:
>  x = get_next()
>break if x:
>  whatever(x)

That is something I'd like too, except: 
- new keyword "loop",
- do we want to make "while" obsolete?
- need two kinds of "break" (one impact "else" the other does not).


>Basically, I don't like multiple actions in the same line.  I
>like vertical arrangement of code.  I find it easier to read and
>easier to understand.

Me too, but not if it requires more nested structures, duplicate code, or
temporary variables for flow-control purpose only.  See below.


>for line in iter(readline, ""):

Not every action can be changed to iterators.  See below.


>>            if x = dict[a]; x:              proc1(x)
>>            elif x = next(x); x.ok():       proc2(x)
>>            elif x.change(); property(x):   proc3(x)
>>            ...
>
>Need a real life example here.  Is there something in the standard
>library which would be improved with this change?  The reason I
>ask is because this code can be refactored into a function.

if m = re.match(patt1, x); len(m.groups())>3:
    a = process_header(m)
elif m = re.match(patt2, x); m:
    b = process_body(m, some_other_data)
...


>def funky_function(dict, a, x):
>    x = dict[a]
>    if x:
>        return proc1(x)
>    x = next(x)
>    if x.ok():
>        return proc2(x)
>    x.change()
>    if property(x):
>        return proc3(x)

Do you suggest that the normal way to use such control structures is to
always enclose them in a function?  It is almost identical to my hack using
a while loop that was immediately following this example, except being less
obvious (in another scope) and possibly slower:

     while 1:
         x = dict[a]
         if x:  proc1(x); break
         x = next(x)
         if x.ok():  proc2(x); break
         x.change()
         if property(x): proc3(x); break
         ...
         break


>You can add qualifications to make a function call harder to do,
>but I'm betting they aren't common in real life.

I'd say the above regular expression example is quite common, and your
function would need quite some optional variables.


>but increasing the temptation for people to write
>
>  a = f(x)
>  if a > 2:
>    g()
>
>as
>
>  if a = f(x); a > 2:
>    g()

Good point.  Although I do not see the temptation, I don't see the use,
either.  Maybe it should not be allowed after "if", only after "elif".


>Here's a single typing error.
>
>if x > 1;0:
>  ...
>
>when it should have been
>
>if x > 1.0:
>  ...

If we are not considering typos between ";" and ":", this can already happen

x = 1;0; y = 2.0
if x > 1,0:
   ...


>
>>            - mistype == for = in statement will be detected
>
>How?  An expression is a statement.

What was I thinking?  You are right.  Nothing can automatically prevent this.


>Quick! Spot the colon!
>
>if a; \
>   b; \
>   c; \
>   d: \
>   e; \
>   f; \
>   g

I would rather consider this as contrived.  :-)


>>                while char=file.readline()[3]; char != 'x':
>>                    process(char)
>
>To quote Winnie-the-Pooh, I am a programmer of very little brain.
>I forget things too easily, so I like to step through what I'm doing.
>
>for line in iter(file.readline, ""):
>  char = line[3]
>  if char != 'x':
>    break
>  process(char)

Maybe our intuition is different, but it appears to me that 

      while char=file.readline()[3]; char != 'x':

is exactly following things one step at a time, in the right order.

But more seriously, is it practical to change every while loop to for-loops
with iterators?  Consider my other example you ignored

    while string = raw_input(prompt): not string.startswith("n"):
        do things with string
        break the loop according to condition
        change prompt according to condition
        do something more

In practice it is not always a good idea to put every code block in a
separate function, although it might be an ideal goal in some style.

    
>This is also easier to debug.  I can stick in a "print line" and
>see what's going on.  It calls for more work to change the original
>code to do that.

True, but not very much.

      while line=file.readline(); char=line[3]; char != 'x':

>Yes, it's 5 lines compared to 2.  Again, your example is contrived.
>The real code might look like
>
>  commands = (
>    (3, 'x', None),
>    (0, 'reset', do_reset),
>    (4, 'fly', use_swatter),
>  )
>  for line in file:
>    for cmd in commands:
>      if line[cmd[0]:].startswith(cmd[1]):
>        f = cmd[2]
>        if f is None:
>            return
>        f(line)
>

This example does not fit the pattern.  This proposal is not meant to
replace all the usage of "for" by "while".  On the other hand, your
alternatives seem to recommend changing all the "while" to "for".


>>                while string = raw_input(prompt): not
>string.startswith("n"):
>>                    process(string)
>
>Should be a semicolon there ;)

Can be detected automatically. :-)


>You didn't mention
>
>loop:
>  statements
>break if expr:
>  statements
>
>as an alternative, with various spellings of 'loop' and 'break if'.
>One with no new keywords is
>
>while expr:
>  statements
>break if expr:
>  statements

Now I do.  :-) (See near top.)  I'll add it to the PEP.  The main issue is
that it does not distinguish two kinds of "break" (in terms of interaction
with "else").


To most of the alternatives you mention my immediate reaction is one of
these two questions:

1. Is it practical to change all while loops to for-loops with iterators?
2. Is it practical to change all elif into nested scope with break / return?

I'd guess no.  Of course for any simple example it would appear so, and any
complicated example may appear contrived.  


Huaiyu




More information about the Python-list mailing list