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

Cliff Wells cliff at develix.com
Sun Sep 14 10:44:24 CEST 2008

```On Sun, 2008-09-14 at 01:36 -0700, Cliff Wells wrote:
> On Sun, 2008-09-14 at 01:25 -0700, Cliff Wells wrote:
> > On Sun, 2008-09-14 at 08:36 +0100, Arnaud Delobelle wrote:
> > > On 14 Sep 2008, at 07:36, Cliff Wells wrote:
> > >
> > > > On Sun, 2008-09-14 at 07:23 +0100, Arnaud Delobelle wrote:
> > > >> On 13 Sep 2008, at 23:17, Cliff Wells wrote:
> > > >>
> > > >>> On Sat, 2008-09-13 at 19:01 +0100, Arnaud Delobelle wrote:
> > > >>>>
> > > >>>> So what does:
> > > >>>>
> > > >>>> a = (if False: 1)
> > > >>>>
> > > >>>> evaluate to?
> > > >>>
> > > >>> That's a good question.  This is one of those areas where a
> > > >>> definition
> > > >>> would need to be created.  My inclination is to say None (much
> > > >>> like a
> > > >>> function with no return statement).
> > > >>>
> > > >>
> > > >> Assuming the return value of "None", I go back to an example I gave
> > > >> earlier:
> > > >>
> > > >>    factors = for x in range(2, n):
> > > >>        if n % x == 0:
> > > >>            x
> > > >>
> > > >> This doesn't work as intended (filtering out the non-factors).  How
> > > >> to
> > > >> make it work?  The only way I can think of is to make (if 0: 1)
> > > >> return
> > > >> a special "non-value" which loops will then filter out.  But then we
> > > >> all know what happens to non-values.
> > > >>
> > > >> So how would you solve this problem?
> > > >
> > > > By writing it properly ;-)
> > > >
> > > > factors = for x in range ( 2, n ):
> > > >    if n % x == 0:
> > > >        yield x
> > > >
> > > > As I mentioned previously, in order to merge the concept of generator
> > > > with a for-expression would require bringing in the yield keyword,
> > > > just
> > > > as it does now for generator functions.
> > > >
> > > > The example you gave would evaluate to None (or perhaps an empty
> > > > list or
> > > > generator - that's a detail that would take more consideration before
> > > > defining it).
> > > >
> > >
> > > OK, but this seems to me incompatible with current Python:
> > >
> > > def chain(I, J):
> > >      for i in I: yield i
> > >      for j in J: yield j
> > >
> > > Currently
> > >
> > >  >>> '-'.join(chain('spam', 'eggs'))
> > > 's-p-a-m-e-g-g-s'
> > >
> > > With your proposal, the first *expression* (for i in I: yield i) will
> > > evaluate to something like iter(I) and then be discarded.  Then the
> > > second *expression* (for j in J: yield j) will evaluate to something
> > > like iter(J) which will be discarded.  So chain('spam', 'eggs') will
> > > return None.
> >
> > It seems you have me on this one.  There's clearly other ways to do the
> > same thing, but since backwards-compatibility is a prerequisite I'll
> > have to concede the point.
> >
> > A potential solution would to be to use a different keyword than "yield"
> > to separate current syntax from my proposed syntax (that is, distinguish
> > expression-scoped yield from function-scoped yield), and just side-step
> > the issue, but that seems unappealing to me.
>
> Actually, a few more minutes of pondering got me a solution I don't find
> abhorrent.  Let yield mean what it currently does.  Instead, let
> "continue" accept an optional parameter (like "return").  Then your
> above example continues to work and my proposed change would look like:
>
> for i in j:
>     continue i
>
> I haven't considered this too deeply, but it is at least consistent with
> "return" syntax and doesn't add a new keyword.

I'm probably replying way too fast (in fact, I know I am), but I have
two thoughts on this:

1) it seems to alter the semantics of "continue" too much when
considered against current syntax, but...

2) with the new syntax, it seems not too bad because

j = range(3)
for i in j: i  # evaluates to []
for i in j: continue # evaluates to []
for i in j: continue i # evaluates to [0,1,2]

Overall I'm a bit torn on the idea.  Thoughts?

Regards,
Cliff

```