On Fri, 24 Jun 2022 at 13:26, Joao S. O. Bueno <jsbu...@python.org.br> wrote:
>
>
>
> On Thu, Jun 23, 2022 at 2:53 AM Chris Angelico <ros...@gmail.com> wrote:
>>
>> On Thu, 23 Jun 2022 at 11:35, Joao S. O. Bueno <jsbu...@python.org.br> wrote:
>> >
>> > Martin Di Paola wrote:
>> > > Three cases: Dask/PySpark, Django's ORM and selectq. All of them
>> > > implement deferred expressions but all of them "compute" them in very
>> > > specific ways (aka, they plan and execute the computation differently).
>> >
>> >
>> > So - I've been hit with the "transparency execution of deferred code" 
>> > dilemma
>> > before.
>> >
>> > What happens is that: Python, at one point will have to "use" an object - 
>> > and that use
>> > is through calling one of the dunder methods. Up to that time, like, just 
>> > writing the object name
>> > in a no-operation line, does nothing. (unless the line is in a REPL, which 
>> > will then call the __repr__
>> > method in the object).
>>
>> Why are dunder methods special? Does being passed to some other
>> function also do nothing? What about a non-dunder attribute?
>
>
> Non-dunder attributes goes through obj.__getattribute__  at which point 
> evaluation
> is triggered anyway.

Hmm, do they actually, or is that only if it's defined? But okay. In
that case, simply describe it as "accessing any attribute".

>> Especially, does being involved in an 'is' check count as using an object?
>
>
> "is" is not "using', and will be always false or true as for any other object.
> Under this approach, the delayed object is a proxy, and remains a proxy,
> so this would have side-effects in code consuming the object.
> (extensions expecting strict built-in types might not work with a
> proxy for an int or str) - but "is" comparison should bring 0 surprises.

At this point, I'm wondering if the proposal's been watered down to
being nearly useless. You don't get the actual object, it's always a
proxy, and EVERY attribute lookup on EVERY object has to first check
to see if it's a special proxy.

>> dflt = fetch_cached_object("default")
>> mine = later fetch_cached_object(user.keyword)
>> ...
>> if mine is dflt: ... # "using" mine? Or not?
>>
>> Does it make a difference whether the object has previously been poked
>> in some other way?
>
>
> In this case, "mine" should be a proxy for the evaluation of the call
> of "fetch_cached_object" which clearly IS NOT the returned
> object stored in "dflt".
>
> This is so little, or so much, surprising as verifying that "bool([])" yields 
> False:
> it just follows the language inner workings, with not special casing.

If it's defined as a proxy, then yes, that's the case - it will never
be that object, neither before nor after the undeferral. But that
means that a "later" expression will never truly become the actual
object, so you always have to keep that in mind. I foresee a large
number of style guides decrying the use of identity checks because
they "won't work" with deferred objects.

> Of course, this if this proposal goes forward - I am just pointing that the
> existing mechanisms in the language can already support it in a way
> with no modification. If "is" triggering the resolve is desired, or if
> is desired the delayed object should  be replaced "in place", instead
> of using a proxy, another approach would be needed - and
> I'd favor the "already working" proxy approach I presented here.
>
> (I won't dare touch the bike-shedding about the syntax on this, though)
>

Right, but if the existing mechanisms are sufficient, why not just use
them? We *have* lambda expressions. It wouldn't be THAT hard to define
a small wrapper - okay, the syntax is a bit clunky, but bear with me:

class later:
    def __init__(self, func):
        self.func = func
        self.__is_real = False
    def __getattribute__(self, attr):
        self.__makereal()
        return getattr(self.__wrapped, attr)
    def __makereal(self):
        if self.__is_real: return
        self.__wrapped =  self.func()
        self.__is_real = True

x = later(lambda: expensive+expression()*to/calc)

And we don't see a lot of this happening. Why? I don't know for sure,
but I can guess at a few possible reasons:

1) It's not part of the standard library, so you have to go fetch a
thing to do it. If that's significant enough, this is solvable by
adding it to the stdlib, or even a new builtin.

2) "later(lambda: expr)" is clunky. Very clunky. Your proposal solves
that, by making "later expr" do that job, but at the price of creating
some weird edge cases (for instance, you *cannot* parenthesize the
expression - this is probably the only place where that's possible, as
even non-expressions can often be parenthesized, eg import and with
statements).

3) It's never actually the result of the expression, but always this proxy.

4) There's no (clean) way to get at the true object, which means that
all the penalties are permanent.

5) Maybe the need just isn't that strong.

How much benefit would this be? You're proposing a syntactic construct
for something that isn't used all that often, so it needs to be a
fairly dramatic improvement in the cases where it _is_ used.

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/JTRM6QULV6LPUSKMXF5O7YWELRKY7HNJ/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to