[Python-ideas] PEP 572: Statement-Local Name Bindings

Paul Moore p.f.moore at gmail.com
Fri Mar 2 08:26:38 EST 2018


On 2 March 2018 at 12:48, Nick Coghlan <ncoghlan at gmail.com> wrote:
> The design intent related rationale stems from the fact that closed over
> references can live for an arbitrarily long time (as can regular function
> locals in a generator or coroutine), and I think statement locals should be
> as reliably ephemeral as we can reasonably make them if they're going to be
> different enough from function locals to be worth the hassle of adding them.
>
> So that means asking a bunch of questions and deliberately giving the
> *opposite* answer for statement locals than I would for function locals:
>
> * Visible in locals()? Yes for function locals, no for statement locals
> * Visible in frame.f_locals? Yes for function locals, no for statement
> locals
> * Prevents access to the same name in outer scopes? Yes for function locals,
> no for statement locals
> * Can be closed over? Yes for function locals, no for statement locals
>
> Answer "no" to all those questions is only reasonable if statement local
> references *look* different from regular variable names. But I also think we
> need to proposing answering "No" to all of them to make statement locals
> potentially interesting enough to be worth considering.

OK, that argument makes sense to me. At least in the sense that it
makes a good case for how statement-local names should work *if* we
adopt them. I reserve the right to change my mind, as I haven't
thought this through fully, but at least superficially I'm with you
this far.

I will note that I don't see this as a compelling reason for *having*
them, just a good analysis of how they might behave if we do.

> Neither PEP 527 nor 3150 *needs* the syntactic markers - the compiler can
> figure out what is going on because it does the symbol table analysis pass
> before the code generation pass, and hence can tag names appropriately based
> on what it finds.
>
> My concern is for people reading the code, where omitting a syntactic marker
> also forces *humans* to read things in two passes to make sure they
> understand them correctly. Consider this example:
>
>     x = 10
>     data = [x*x for i in range(10)]
>
> This will give you a 10 item list, where each item is 100.
>
> But now consider a world with statement locals, where statement locals use
> the same reference syntax as regular locals:
>
>     x = 10
>     data = [x*x for i in range(10) if (12 as x)]
>
> That's a deliberately pathological example (and you can already write
> something similarly misleading using the "for x in [12]" trick), but the
> fact remains that we allow out of order evaluation in expressions in a way
> that we don't permit for statements.

OK. That's my concern as well. But my conclusion is different - I view
this as a pretty strong argument that the complexity cost is too high
to justify the feature, rather than as a difficulty we need to
mitigate in order to make the feature usable.

> With a syntactic marker though, there's typically going to be less ambiguity
> about where a name comes from:
>
>     x = 10
>     data = [.x*.x for i in range(10) if (12 as .x)]
>
> It's not a panacea (since you may still be shadowing a name from an outer
> statement), and adapting it for PEP 3150 isn't without it's problems
> (specifically, you need to allow ".x = 12" in the given clause to make the
> names match up), but it should be less confusing than allowing a new
> subexpression to interfere with name resolution semantics folks have been
> relying on for years.

On my screen right now, I can barely see the dots. That's in email
with a proportional font, so not "real coding", but it's surprising
(and somewhat depressing :-() to think that probably the majority of
code I read these days is in emails.

So I don't think that this is a good enough fix to warrant making
Tim's screen look gritty.

> If statement locals behave just like function locals, then there's no reason
> to add them to the language in the first place - "(expr as name)" would just
> become a confusing second way to spell "name = expr".

Well, the whole reason this debate keeps coming up is because people
keep finding places they want to type "name = expr" but they can't,
because their context isn't a statement. We're basically trying to
design a replacement for "name = expr" that can be used in an
expression. And the status quo is "refactor your expression into
multiple statements". Doing so isn't always ideal (and particularly
grates on people coming from languages where assignments are
expressions, like C/C++) but it is always possible.

Adding "mustn't just be another way to spell name = expr" to the
requirements is an extra requirement - and arguably one that
contradicts the original requirement which was "find a way to allow
name = expr in expressions".

Designing a broader feature which solves the original problem is a
good goal, but we need to take care not to introduce scope creep or
over generalisation. In this case, IMO, we're not doing that (yet!)
but we are hitting design problems which are orthogonal to the
original requirement.

> It's only potentially worthwhile if statement locals offer us something that
> function locals don't, and the clearest potential candidate for that
> differentiation is to provide a greater level of assurance regarding
> locality of use than regular name binding operations do.

I disagree. It's *still* potentially worthwhile if it just offers a
clean resolution for people who want to name complex sub-parts of a
comprehension. But the bar for "clean" in that case is higher, because
the benefit is pretty limited. I don't think it reaches that higher
bar, but I also am not sure that the benefits of the wider proposal
are sufficient to warrant the amount of lowering of the bar that is
needed. (That metaphor got way too strained. I hope it still made
sense).


>> I guess I remain -1 on the proposal, and nothing that's getting said
>> about how we can make it work is doing anything to persuade me
>> otherwise (quite the opposite).
>
> Yep, that's fair, as there are *lots* of viable alternatives to inline
> naming of subexpressions (each with various trade-offs). The question at
> hand is whether we can come up with semantics and syntax that folks actually
> like well enough to put to python-dev for a yes/no decision, with the pros
> and cons consolidated in one place.

Precisely.

And the usual proviso that "status quo wins" applies strongly here,
where (as noted in Chris' PEP) there are already *many* existing
solutions.

Paul


More information about the Python-ideas mailing list