[Python-ideas] Explicit variable capture list

Andrew Barnert abarnert at yahoo.com
Wed Jan 27 15:49:12 EST 2016


On Jan 26, 2016, at 15:59, Greg Ewing <greg.ewing at canterbury.ac.nz> wrote:
> 
> I'd like to do something with "let", which is famliar
> from other languages as a binding-creation construct,
> and it doesn't seem a likely choice for a variable
> namne.
> 
> Maybe if we had a general statement for introducing
> a new scope, independent of looping:
> 
>  let:
>    ...

A few years ago, I played with using an import hook to add let statements to Python (by AST-translating them to a function definition and call). It's a neat idea, but I couldn't find any actual uses that made my code more readable. Or, rather, I found a small a handful, but every time it was actually far _more_ readable to just refactor the let body out into a separate (non-nested) function or method.

I don't know if this would be true more universally than for my code. But I think it's worth trying to come up with non-toy examples of where you'd actually use this.

Put another way: flat is better than nested. When you actually need a closure, you have to go nested--but most of the time, you don't. And if you go flat most of the time, the few cases where you go nested now signal that something is special (you actually need a closure). So, unless there really are common cases where you need a closure over some variables, but early binding/value capture/whatever for others, I think this may harm readability more than it helps.

> The for-loop is a special case, because it assigns a
> variable in a place where we can't capture it in a
> let-block. So we introduce a variant:
> 
>  for let x in things:
>    funcs.append(lambda: process(x))

This reads weird to me. I think it's because I've been spending too much time in Swift, but I also think Swift may have gotten things right here, so that's not totally irrelevant.

In Swift, almost anywhere you want to create a new binding--whether normal declaration statements, the equivalent of C99 "if (ch = getch())", or even pattern matching--you have to use the "let" keyword. But "for" statements are the one place you _don't_ use "let", because they _always_ create a new binding for the loop variable.

As I've mentioned before, both C# and Ruby made breaking changes from the Python behavior to the Swift behavior, because they couldn't find any legitimate code that would be broken by that change. And there have been few if any complaints since. If we really are considering adding something like "for let", we should seriously consider whether anyone would ever have a good reason to use "for" instead of "for let". If not, just change "for" instead.

> 2) It may be desirable to allow assignments on the
> same line as "let", e.g.
> 
>  with open(filename) as f:
>    let g = f:
>      process(g)
> 
> which seems marginally more readable.

It's also probably a lot more familiar to people who are used to let from functional languages. And I don't _think_ it's a misleading/false-cognate kind of familiarity, although I'm not positive about that.


More information about the Python-ideas mailing list