[Python-ideas] If branch merging

Nick Coghlan ncoghlan at gmail.com
Mon Jun 8 12:32:44 CEST 2015

On 8 June 2015 at 14:24, Andrew Barnert <abarnert at yahoo.com> wrote:
> On Jun 7, 2015, at 20:41, Nick Coghlan <ncoghlan at gmail.com> wrote:
> On 8 June 2015 at 12:45, Chris Angelico <rosuav at gmail.com> wrote:
> On Mon, Jun 8, 2015 at 12:33 PM, Stephen J. Turnbull <stephen at xemacs.org>
> wrote:
> I'm definitely -1 on the also, alif syntax at this point.  On the
> other hand, having done a lot of C programming in my misspent youth, I
> do miss anaphoric conditionals, so I too would like to see the
> possibility of "if cond as var: do_something_with_var" explored.  Of
> course Nick is right that automatic common subexpression elimination
> (CSE) is the big win, but manual CSE can improve readability.
> Part of the trouble with depending on CSE is that Python is so dynamic
> that you can't depend on things having no side effects... but the more
> important part, in my opinion, is that duplication is a source code
> maintenance problem.
> Yes, this is the part of the problem definition I agree with, which is
> why I think named subexpressions are the most attractive alternative
> presented in the past discussions.
> The problem with general named subexpressions is that it inherently means a
> side effect buried in the middle of an expression. While it's not
> _impossible_ to do that in Python today (e.g., you can always call a
> mutating method in a comprehension's if clause or in the third argument to a
> function), but it's not common or idiomatic.
> You could say this is a consulting-adults issue and you shouldn't use it in
> cases where it's not deep inside an expression--but those are the actual
> motivating cases, the ones where just "pull it out into a named assignment"
> won't work. In fact, one of our three examples is:
>    [b for a in iterable if (a.b as b)]
> That's exactly the kind of place that you'd call non-idiomatic with a
> mutating method call, so why is a binding not even worse?

Ah, but that's one of the interesting aspects of the idea: since
comprehensions and generator expressions *already* define their own
nested scope in Python 3 in order to keep the iteration variable from
leaking, their named subexpressions wouldn't leak either :)

For if/elif clauses and while loops, the leaking would be a desired
feature in order to make the subexpression available for use inside
the following suite body.

That would leave conditional expressions as the main suggested use
case where leaking the named subexpressions might not be desirable.
Without any dedicated syntax, the two ways that first come to mind for
doing expression local named subexpressions would be:

    x = (lambda a=a: b if (a.b as b) else a.c)()
    x = next((b if (a.b as b) else a.c) for a in (a,))

Neither of which would be a particularly attractive option.

The other possibility that comes to mind is to ask the question: "What
happens when a named subexpression appears as part of an argument list
to a function call, or as part of a subscript operation, or as part of
a container display?", as in:

    x = func(b if (a.b as b) else a.c)
    x = y[b if (a.b as b) else a.c]
    x = (b if (a.b as b) else a.c),
    x = [b if (a.b as b) else a.c]
    x = {b if (a.b as b) else a.c}
    x = {'k': b if (a.b as b) else a.c}

Having *those* subexpressions leak seems highly questionable, so it
seems reasonable to suggest that in order for this idea to be workable
in practice, there would need to be some form of implicit scoping rule
where using a named subexpression turned certain constructs into
"scoped subexpressions" that implicitly created a function object and
called it, rather than being evaluated inline as normal. (The dual
pass structure of the code generator should make this technically
feasible - it would be similar to the existing behaviour where the
presence of a yield expression changes the way a containing "def"
statement is handled)

However, that complication is significant enough to make me wonder how
feasible the idea really is - yes, it handles simple cases nicely, but
figuring out how to keep the side effect implications to a manageable
level without making the scoping rules impossibly hard to follow would
be a non-trivial challenge. Without attempting to implement it, I'm
honestly not sure how hard it would be to introduce more comprehension
style implicit scopes to bound the propagation of named subexpression


Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia

More information about the Python-ideas mailing list