On Mon, Dec 06, 2021 at 03:14:36AM +1100, Chris Angelico wrote:

> Closures cannot be executed without a context. Consider:
> 
> def f(x=lambda: (a:=[])):
>     if isinstance(x, FunctionType): x = x()
>     print(a)
> 
> Here's the problem: The name 'a' should be in the context of f,

Not in the code as you show it. The a in the signature is local to the 
lambda, and the a in the print() call is a global. The code exactly as 
shown works fine, in exactly that way.

So I'm going to assume that you meant:

    def f(x=>(a:=[]))

which compiles to a separate `lambda:(a:=[])`, as per my suggestion.


> but that context *does not exist* until f starts executing.

If this really cannot be solved, then we could prohibit walrus operators 
in late bound defaults. If something is too hard to get right, we can 
prohibit it until such time (if ever) that we work out how to do it. For 
many years, we had a restriction that you could have try...except and 
you could have try...finally but you couldn't have try...except... 
finally in a single block.

(And then we solved that technical limitation.)

Or we make them global, like they are for early bound defaults. Its not 
*mandatory* that walrus bindings in the default expression go into the 
function locals. They could go into the function's surrounding scope 
(usually globals). That's a perfectly acceptable solution too.

Or... be bold. Think outside the box. "Do not go where the path may 
lead, go instead where there is no path and leave a trail." To boldly go 
where no science fiction show has gone before, and other cliches.

If we can't execute the expression without the context existing, we make 
it exist. Details to follow in another post.


> As an
> early-bound default, like this, it's not going to work, because the
> function object has to be fully constructed at function definition
> time.

This paragraph confused me for the longest time, because as an 
early-bound default, it does work. If you put `return x` after the 
print, you get the expected result:

>>> a = "this is a global"
>>> f()
this is a global
[]


> If you try to do this sort of thing with a magical function that is
> synthesized as part of late-bound default handling, you'll still need
> to figure out when f's context gets formed. Normally, it won't get
> formed until the stack frame for f gets constructed - which is when
> arguments get assigned to parameters, etc, etc. Trying to call that
> inner function without first giving it a context won't work.

Right. So make the context.


[...]
> If you want to write up a competing reference implementation, go
> ahead. I don't think it will be as easy as you claim. And I'm not
> going to mention the possibility in the PEP *without* a reference
> implementation, nor do I intend to write one myself (since I dispute
> its usefulness).

It is the job of the PEP to describe rejected alternatives. If you 
choose to disregard my clearly superior suggestion *wink* but don't 
explain why you are rejecting it, then the PEP is not doing its job.


-- 
Steve
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/ELUF467UH4U3PIIHDJOCP36ATAQFLCXA/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to