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

Andrew Dalke dalke at dalkescientific.com
Wed Oct 17 20:58:07 EDT 2001


Huaiyu Zhu:
>        cannot be written in 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"
>
>        This is because there are two breaks that have different semantical
>        meanings.  The fully equivalent version in current syntax has to
use
>        one extra variable to keep track of the breaks that affect the else

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


>    4.1. Action needed before condition:
>
>            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)

(with variations of the spelling - I don't recall the details
of what came up)

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.

>    4.2. Condition does not need to be a method of an object in assignment:
>
>            while line = readline(); 'o' in line:
>                line = process(line)
>                if 'e' in line: break
>            else:
>                print "never met break"

for line in iter(readline, ""):
  if 'o' in line:
    print "never met break"  # Really, "never saw an 'e'"
    break
  line = process(line)
  if 'e' in line:
    break

This one extra line if you (unlike me) put the 'break' after
if's ":".)  And since you like code after semicolon,

for line in iter(readline, ""):
  if 'o' in line:
    print "never saw an 'e'"; break
  line = process(line)
  if 'e' in line:
    break

>    4.4. More complex example:
>
>            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.

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)

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

>    It is seen that the new syntax remove substantial amount of clutter,

in contrived cases

>    thereby increasing readability and expressiveness.

but increasing the temptation for people to write

  a = f(x)
  if a > 2:
    g()

as

  if a = f(x); a > 2:
    g()

which is *less* readable because it is *more* expressive.

> This structure is safe against single typing errors:

Here's a single typing error.

if x > 1;0:
  ...

when it should have been

if x > 1.0:
  ...

>            - mistype == for = in statement will be detected

How?  An expression is a statement.

>        Since the change is only in the syntax of "if", "elif" and "while",
>        not in the fundamentals of expressions and statements, there is not
>        much more chance of obfuscation than existing syntax.

Famous last words.  :)

Quick! Spot the colon!

if a; \
   b; \
   c; \
   d: \
   e; \
   f; \
   g

This isn't possible now because the first ";" or ":"-like symbol after
the 'if' must be a ':' else Python would complain.


>    We show that the following alternatives have more problems than the
>    proposed extension.
 ...
>    6.3. Using iterators:  In Python 2.2, it is possible to write
>
>                for line in file:
>                    if line=='end': break
>                    process_line(line)
>
>        in place of
>
>                while line=file.readline(); line != 'end':
>                    process_line(line)
>
>        However, this does not solve the problem we are considering
>        completely. It is more suitable for objects that are naturally used
>        (and reused) in iterations so that it is profitable to create
>        iterators for them.  It is not practical to define an iterator for
>        every action that might go before a condition:
>
>                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)

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.

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)


>                while string = raw_input(prompt): not
string.startswith("n"):
>                    process(string)

Should be a semicolon there ;)


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

but all this does is save one line over

while expr:
  statements
  if expr:
    break


But-then-again-it-took-me-a-while-to-like-list-comprehensions-ly y'rs

                    Andrew
                    dalke at dalkescientific.com






More information about the Python-list mailing list