[Python-Dev] re: syntax feedback from LANL course (very long)

gvwilson@nevex.com gvwilson@nevex.com
Thu, 3 Feb 2000 15:00:04 -0500 (EST)


I taught Python at Los Alamos National Laboratory for the second time
two weeks ago, and finally found time last night to go through both
sets of feedback forms.  Given the current discussion on python-dev of
ternary conditionals, namespaces, etc., I figured syntax issues would
be most topical.

Most of the students were in their 20's or 30's, with a handful in their
40's and 50's.  When asked what they used on a daily basis, they split
pretty evenly between Fortran and C++ (no C-but-not-C++ responses).  They
also divided pretty evenly between "numerical and/or visualization" and
"systems programming".  (At the lab, the latter means everything from
making the web archive of past experimental results searchable, through to
porting HDF-5 to massively-parallel machines and hacking the Linux kernel
to make inter-process communication run faster.)  28 students had Ph.D.'s
(all in math, physical science, or engineering); nine had M.Sc.'s (one in
C.S.), and the three B.Sc.'s were all in C.S.

So here goes...

-------------------------------------------------------------------------

0. "Hey, using indentation to show nesting is cool!"

'Nuff said --- thanks, Guido.



-------------------------------------------------------------------------

1. "What's with 'while 1: break' for normal loops?"

This was the most common complaint about syntax --- neither Fortran
nor C programmers found it natural to create an infinite loop, then
jump out of it.  (Several of the C++ programmers said that house style
in their groups only allows 'break' for truly exceptional cases.)

One student suggested the following loop-and-a-half notation:

        do:
            first-half
        while condition:
            second-half

which has the nice property that both of the degenerate forms:

        do:
            first-half
        while condition # no trailing ':'

and

        while condition:
            second-half

are useful in their own right.  Tim Peters tells me that this has been
discussed many times before, and that the main obstacle is the
introduction of a new keyword.  He mentioned:

        while:
            first-half
        and while condition-1:
            second-half
        and while condition-2:
            third-half # [sic]
        and while final-condition # no trailing ':'

as an interesting (but possibly confusing) generalization.



-------------------------------------------------------------------------

2. "Using range() in for loops is clumsy."

My audience does a lot of 'for' loops over numerical bounds, and would
prefer something slice-ish like:

        for i in 0:10:2 :
            body

I think they could live with:

        for i in [0:10:2] :
            body

I believe Brian Harvey mentions somewhere in "Computer Science Logo
Style" (the best programming books for kids I've ever seen) that it
was important to make basic counting loops very, very simple to write.
It's a different audience (10-year-olds instead of Ph.D.'s with 30
years of Fortran behind them), but maybe worth examining.

(While we're on the topic: is there an easy way to construct a slice
like 3:10, pass it around as a variable, and later use it to index an
arbitrary sequence?)



-------------------------------------------------------------------------

3. "Where is '+=' ?" and "Why can't I redefine assignment?"

To my surprise, no-one asked why assignment wasn't an operator.
However, a lot of people wanted in-place modification --- it's one of
the innovations of C and derived languages that scientific programmers
appreciate, since it saves them having to write
'pressure_gradient[(ix+1)*3+idx][iy-1-(idx%2)]' on both sides of an
assignment, and then remember to update both occurrences when they
notice the typo.  (The '%' should be a '/'.)

Several of the students who ticked the box "Familiar with
object-oriented programming" asked why they could redefine addition,
membership, etc., but not straight assignment.  Guido explained the
reasoning to me at IPC8, and pointed out that classes can always
define a '.set(...)' method.  However, I'm pretty sure that 'set()'
will be a non-starter with this crowd (I can explain why if people
care).



-------------------------------------------------------------------------

3.1 Min and Max

On a related note, I also had requests for redefining "min" and "max"
(e.g. to handle objects representing bounding volumes in 3D graphics).
As a certain kind of mathematician will point out, these are really
binary operators, just like "+", and it's only an historical accident
that they aren't treated with the same respect (I'm quoting here).

I mentioned this to Guido, and suggested the C* notation:

        a = x <? y # min
        b = x >? y # max

He said (rightly) that '<?' and '>?' won't be familiar even to experienced
programmers, but that user-definable 'min' and 'max' might be do-able.  
The only issue then is that if '+=' makes it into the language, something
like 'min=' ought to as well...



-------------------------------------------------------------------------

3.2 Case Statement, and Remembering Matches in Conditionals

Another related point came up in discussion of regular expressions.  The
code I showed them was:

        pat1 = re.compile(...)
        pat2 = re.compile(...)
        ...etc...

        while 1:
            line = ...get input...

            m = pat1.match(...)
            if m:
                code
                continue

            m = pat2.match(...)
            if m:
                code
                continue

            ...etc...

Several students said that it wasn't at all clear that the various
matches were intended to be mutually exclusive; one student became
very frustrated trying to debug this code after accidentally deleting
a 'continue'.  If there's a cleaner way to structure this, I'd be
grateful for an example.

One student (a physicist who now does computer graphics) sent me:

        if x is:
            expr1, expr2:
                code using x (which is either val1 or val2)
            expr3:
                code using x (which is guaranteed to be val3)
            else:
                code using x (which is something else)

which would make the above:

        while 1:
            line = ...get input...

            if m is:

                pat1.match(...):
                    code using m

                pat2.match(...):
                    code using m

                etc.

(I'm not advocating, I'm just reporting...)



-------------------------------------------------------------------------

4. "Aren't tuples redundant?"

I explained that the const-ness of tuples was needed so that they
could be used as dictionary keys.  The guy with Perl in his background
immediately asked if that's reliable --- a tuple can contain a list,
which can be mutated. You've all heard this one more times than I
have...



-------------------------------------------------------------------------

5. "Why can't I put an 'except' after an 'if'?"

This one surprised me.  Several students wanted to be able to say:

        if (dict['fred'] > 0):
            code
        except KeyError:
            other-code

or:

        for i in seq:
            i = i ** 2
        except ArithmeticError:
            error-handling-code

or even (from one guy with Perl in his background):

        dict['fred'] = dict['fred'] + 1
        except KeyError:
            dict['fred'] = 1

They pointed out that 'try' does nothing except introduce a block, so
why not just use the blocks that other keywords introduce?  I'd be
interested in knowing whether other people's students think like
this... :-)



-------------------------------------------------------------------------

6. "There is no number six."

That's really all that came up about Python syntax.  None of the
students were OO expects, so meta-classes and the like weren't raised.
Generic programming did come up once, but the guy who asked hadn't
clued in that typing is dynamic.  The same guy also asked why he
couldn't interleave anonymous and named function arguments, as in
"def foo(a, b=3, c, d=5)" also came up, but everybody else who
expressed an opinion said they'd find that confusing.

Hope it's useful,

Greg