[Python-ideas] Statements vs Expressions... why?

Cliff Wells cliff at develix.com
Wed Sep 10 23:18:36 CEST 2008

On Wed, 2008-09-10 at 20:55 +0100, Arnaud Delobelle wrote:
> [Sorry for the private reply earlier]
> On 10 Sep 2008, at 19:43, Cliff Wells wrote:
> > Greetings,
> >
> > Something that has started to annoy me in the last couple of years is
> > the fact that most Python control statements cannot be used as
> > expressions.  I feel this is a pretty deep limitation and personally I
> > don't feel it's well-justified.
> >
> > As I understand it, the reason for the distinction mostly has to do  
> > with
> > the premise "flat is better than nested", which I can understand,  
> > but I
> > don't think carries enough weight anymore.
> >
> > Specifically, I'd like to see things like "if" statements, "for"  
> > loops,
> > etc, become expressions.  This would not preclude them from being used
> > as if they were statements (an expression can stand alone on a line of
> > Python code), but would add a lot of expressiveness to the language as
> > well as make Python more viable for creating DSLs.
> >
> Can you post some sample code to illustrate how statements could be  
> used as expressions?
> Do you propose that we write:
>     y = if x == 0:
>         0
>     else:
>         exp(x**-2)
> instead of:
>     y = 0 if x == 0 else exp(x**-2)

Yes, and parentheses could be used to disambiguate, as anywhere else.

> ? Or, how would you write
>     factors = [x for x in range(2, n) if n % x == 0]
> ?  Something like this maybe:
>     factors = for x in range(2, n):
>         if n % x == 0:
>             x
> Or do you suggest something else?

These are correct, albeit simple examples (you are using only assignment
examples).  To give something more interesting, I'd like to be able to
do things like this:

dispatch = {
    '1': lambda x: (
           for i in range(x): 
               if not x % 2:
                   yield 0
                   yield 1 

    '2': lambda x: (
            for i in range(x):
                yield i  

for i in dispatch[val](1):
    print i

Note that this isn't just about lambda, but rather general

To clarify, I propose *not* making syntax changes that add to the
language or alter the meaning of existing code.  
Rather my proposal is along the lines of "relax this particular syntax
requirement" and let the chips fall where they may.  In other words,
Python 2.x code would still work, it simply would not take advantage of
a particular coding style now available to it.

The key difference between a statement and an expression is that

1) an expression has a return value, a statement does not
2) statements cannot be used inside of expressions 

In short, statements are more-or-less castrated expressions.  They have
no other special features.

> > Additionally, removing statements from Python would also allow the
> > language to be simplified.  No need for a ternary "if" operator with
> > different semantics than a normal "if" statement, "for" loops would be
> > brought closer to generators in functionality, and the perceived
> > limitations of lambda would disappear, amongst other things.  We'd  
> > gain
> > a lot of features found in languages like Lisp and Ruby as a side- 
> > effect
> > (i.e. anonymous code blocks).
> >
> > Overall it seems this design decision is specifically geared toward
> > forcing programmers into an imperative style in order to enforce  
> > program
> > readability.  In Python 1.5, this made a bit of sense, but as Python  
> > has
> > "matured" (or in my view, gotten over-complicated) this makes much  
> > less
> > sense.  Many parts of Python's extensive syntax are explicit  
> > workarounds
> > to this design decision.  So on the one hand we have the perceived
> > danger that programmers will write nested code and on the other we  
> > have
> > an ever-expanding syntax.  I'd take the former any day.
> >
> So do you think readability is not as important now as it was?

Of course not.  I'm saying that due to this limitation, readability is
going down the drain even faster.   It's getting to the point where it's
not possible to keep the whole of Python in your head and I feel that a
significant portion of this is due to this particular inflexibility.

Further, I feel that this limitation forces programmers into using hacks
and magic or overly spread-out code, which itself leads to readability
concerns.  Having used Python for around a decade, I'm quite aware of
the fact that you can happily write tons and tons of nice code with
Python in its current state.  However, because of the direction of my
work (developing a internal DSL in Python) I've suddenly become aware of
this glass ceiling.  I'd bumped into it before back when I was doing a
lot of GUI development, but blamed it on lambda rather than realizing
that it wasn't lambda so much as what I am bringing up now.

> > I've not delved into the internals of the Python interpreter to check,
> > but I suspect that converting most statements to expressions would not
> > be very difficult (changing the grammar definition and generated
> > bytecode a small amount in most cases).
> >
> > Any thoughts on this?  I'm sure it's been brought up before, but I
> > haven't found any definitive discussions on why this rather arbitrary
> > design decision continues to hold in the face of a general migration
> > away from imperative languages (especially when it seems it could be
> > changed without much backwards-compatibility issues).
> I think to call this feature of Python an arbitrary design decision is  
> a misjudgement.  To me it is central to the identity of Python.

Sorry, I misspoke: it's not an arbitrary *decision*, but it is an
arbitrary *distinction*. 

As I said, I'm aware of why this decision was originally made
(prevention of nested code, a.k.a. fear of lisp), but the distinction
itself is completely artificial, created to enforce a model of
programming, rather than for technical or performance reasons.

I agree that it is a distinguishing feature of Python, but I don't think
it is central to Python's identity.  That is, it wouldn't be "not
Python" were it removed.


More information about the Python-ideas mailing list