On Mon, 6 Dec 2021 at 09:45, Stephen J. Turnbull
<stephenjturnb...@gmail.com> wrote:
>
> Rob Cliffe via Python-ideas writes:
>
>  > Nobody has attempted (or at least completed) a PEP, never mind an
>  > implementation, of a "generalized deferred object/type", in the last N
>  > years or decades.
>
> Haskell anything.  Ruby blocks.  Closer to home, properties and closures.
>
> So I don't think the object part is that hard, it's the syntax and
> semantics that's devilish.

At one level, it's trivial. A deferred expression is `lambda:
expression`. Evaluating it is `deferred_expr()`.

What's not at all obvious is the requirements beyond that - what do
people *actually* want that isn't covered by this. The most obvious
answer is that they don't want to have to check for a deferred
expression and explicitly evaluate it, which triggers the question,
when do they want the language to evaluate it for them? "Every time"
doesn't work, because then you can't treat deferred expressions as
first class objects - they keep disappearing on you ;-)

So IMO it's the *requirements* that are hard. Maybe that's just me
using different words for the same thing you were saying, but to me,
the distinction is important. People throw around the term "deferred
object", but everyone seems to think that everyone else understands
what they mean by that term, and yet no-one will give a precise
definition.

We can't have a PEP or an implementation until we know what we're
proposing/implementing.

I don't intend to champion a "deferred objects" proposal, but I do
think that they (whatever they are) would be a better (more general)
solution than late-bound arguments. So here's a possible minimal
definition of what a "deferred object" is. It takes the view that
explicitly requesting the evaluation of a deferred is OK, but people
don't want to have to check it's a deferred before evaluating.

1. `defer EXPR` creates a "deferred object", that is semantically
identical to `lambda: EXPR`, except that it isn't a callable, instead
it's a new type of object.
2. `undefer EXPR` is exactly the same as `EXPR`, except that if `EXPR`
evaluates to a deferred object, it gets called (in the sense of it
being equivalent to a lambda which can be called).

Here's a prototype implementation, and a demonstration of how it would
be used to implement late bound arguments. Please note, I understand
that the syntax here is horrible. That's exactly the point, this needs
language support to be non-horrible. That's what a "deferred
expression" proposal would provide.

# Explicitly creating Deferred objects is horrible, this is the bit
that *really* needs language support
class Deferred:
    def __init__(self, callable):
        self.callable = callable

# This could easily be a builtin function (or an operator if people
prefer syntax) once we have deferred objects.
def undefer(expr):
    if isinstance(expr, Deferred):
        return expr.callable()
    return expr


x = 12
# def f(a=defer x):
def f(a=Deferred(lambda: x)):
    a = undefer(a)
    return a

assert f(9) == 9
assert f() == 12
x = 8
assert f() == 8
assert f(9) == 9

If anyone wants to take this and make a *proper* deferred object
proposal out of it, then please do so. If not, then at a minimum I
think this offers something vaguely concrete to discuss regarding the
"why deferred objects are a more general solution to the late bound
argument" question.

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

Reply via email to