On Wed, 22 Jun 2022 at 11:59, David Mertz, Ph.D. <david.me...@gmail.com> wrote:
>
> Thanks Carl and Chris.  After reading your comments, and thinking some more 
> about it, I agree you are both correct that it only makes sense to have a 
> DeferredObject act like a closure in the scope of its creation.  That really 
> should suffice for anything I could sensibly want; it's enough for Dask, and 
> it's enough for functional programming languages with laziness.
>
> Moreover, the limited laziness that Python currently has also follows that 
> rule.  I also haven't gotten to writing that needed section of the PEP, but I 
> need to address generators and boolean shortcutting as limited kinds of 
> laziness.  Obviously, my PEP is much broader than those, but generators also 
> use lexical scope not dynamic scope.
>
>>> Possibly in my defense,  I think Carl's PEP 690 can do the same thing. :-)
>>
>>
>> I’m not sure what you mean. I don’t think there’s any way PEP 690 can 
>> introduce dynamic scoping like this. Can you give an example?
>
>
> Let me just withdraw that.  I think I might be able to construct something 
> where a module's top-level code does something perverse with the call stack 
> where it winds up getting evaluated that can act like dynamic scoping.  I 
> might be wrong about that; but even if it's technically true, it would need 
> very abnormal abuse of the language (as bad as the lovely zero-argument 
> super() does :-)).
>

So then a deferred object is basically a lambda function that calls
itself when referenced. That's reasonable, and broadly sane...

> I don't think this actually has much effect on encompassing late-binding of 
> default arguments, other than needing to say the arguments contribute to the 
> scope on a left-to-right basis.  But actually, despite writing the section 
> because of recent discussion, PEP-671 has little to do with why I want 
> generalized deferreds.  I've suggested it on a number of occasions long 
> before PEP-671 existed (but admittedly always as a passing thought, not as a 
> detailed proposal... which my draft still is not either).
>
> On one small point Chris mentions, I realized before he commented that there 
> was no need to actually rebind the deferred argument to force evaluation of 
> its default.  Simply mentioning it would force the evaluation.  I found 
> something similar in PEP-690 that reminded me that doing this is plenty:
>
>     def func(items=[], n=later len(items)):
>         n  # Evaluate the Deferred
>         items.append("Hello")
>         print(n)
>
> Of course, that's an extra first line of the function for the motivating case 
> of emulating the sentinel pattern.  But it also does let us *decide* when 
> each deferred gets "fixed in place".  I.e. maybe a, b, and c are all `later` 
> arguments.  We could make the first line `a, b` but only reference `c` at 
> some later point where it was appropriate to the logic we wanted.
>

... but it doesn't work for this case. If a deferred is defined by its
creation context, then the names 'len' and 'items' will be looked up
in the surrounding scope, NOT the function's. It would be like this:

def func(items=[], n=lambda: len(items)):
    n = n()

which, in turn, is similar to this:

_default = lambda: len(items)
def func(items=[], n=None):
    if n is None: n = _default
    n = n()

and it's fairly clear that this has the wrong scope. That's why PEP
671 has the distinction that the late-bound default is scoped within
the function body, not its definition. Otherwise, this doesn't work.

ChrisA
_______________________________________________
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/3VQ4DOILYKKI47AS2EELGHAAI7WPS3B5/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to