This is very much implementation dependent. And I do not have a big opinion 
here as I certainly haven’t spent enough time to have one. I am just 
considering functionality from user’s perspective for the time being.

> Let's tackle just this one part for a moment. What does "ensure_eval"
> do? Evaluate a proxy object but not evaluate anything else?

In case of the library I used, it would look something like:

def ensure_eval(x):
    if isisnstance(x, Proxy) and x.unevaulated:
        x.evaluate()
    return x

> This should always succeed, right? Well, what if x is itself a Proxy
> object? How does it know not to reevaluate it?

Not necessarily. I mean, yes, but only if deferred evaluation is done by 
actually replacing value in the namespace dictionary. In case of this example, 
where this specific package is used, it is not so and is not intended to be so.

When operation is performed, the value is evaluated and returned, but it 
remains proxy object. So if lazy is nested, the whole nesting is evaluated on 
first operation which needs its value.

I see this one as “decision to be made” as opposed to “reason why it’s not 
working”.

I am not sure about the “right” approach here. Actually replacing deferred 
object with a value does sound invasive, although given there was a way to do 
it elegantly and without loss in performance, it seems to be more robust and 
eliminates maintenance of proxy object.

So the big question is, which of the 2 approaches to take:
1) Implementing a robust proxy object.
    Less depth more breadth - ensuring proxy works with all objects / coming up 
with protocols, which have to be implemented for non-standard types to be 
compatible.
    In this case both of assertions will and should fail, although `assert y is 
y_` will always pass.

Example from library:
obj = Proxy(lambda: 1)
obj2 = Proxy(lambda: obj)
obj is obj2         # False
print(obj == obj2)  # True

2) Replacing deferred evaluation with it’s value.
    in this case, a fair bit of low level decisions such as the one you 
indicated would have to be made, a lot of deep strings to pull
    In this case, it very much depends how “is”, “type” and other `things` 
behave with deferred objects. So if `x` is a proxy, and ‘is’ treats proxy 
object and not it’s value (which is reasonable), then assertions will and 
should fail. However, unraveling the whole stack on first evaluation does 
simplify things a bit.Then ` y_ = ensure_eval(y)` in your example is a 
redundant line. In practice, if deferred evaluation is used, one would need to: 
`assert  ensure_eval(x) is ensure_eval(y)`. Also, looking at deferred eval RST 
doc, the suggested mechanics are that expression is evaluated if “later” is not 
re-called. So in theory, it might be reasonable to have `x = later expr() 
<equiv> x = later later later expr()`. Instead of evaluating the whole stack, 
just not allowing it to grow in the first place. Then builtin `ensure_eval` is 
then straight forward single operation at C level, which would mostly be used 
on low level checks, such as asserts in your examples. It could even have its 
syntax instead of builtin function, given there are only 2 entry points 
(definition of deferred & ensuring it’s evaluation). E.g.
def expr():
    print('Evaluating')
    return 1

a = `expr()`
b = `a`             # carry over lazy, but it's a new object at C level
assert a is b       # False
assert !a is !b     # True
assert a is b       # True



> On 21 Jul 2023, at 08:46, Chris Angelico <ros...@gmail.com> wrote:
> 
> On Fri, 21 Jul 2023 at 11:08, Dom Grigonis <dom.grigo...@gmail.com> wrote:
>> Also, can't find a way to ONLY force evaluation without any additional 
>> operations in this specific library. A simple callable which evaluates if 
>> unevaluated & returns would do. Then:
>> 
>> def IF(condition, when_true, when_false):
>>    if condition:
>>        return ensure_eval(when_true)
>>    else:
>>        return ensure_eval(when_false)
>> 
>> Controls evaluation if deferred objects are provided, but can also be used 
>> with `normal` values.
>> 
> 
> Let's tackle just this one part for a moment. What does "ensure_eval"
> do? Evaluate a proxy object but not evaluate anything else? That seems
> simple, but might very well be straight-up wrong. Consider:
> 
> def test_proxy(x):
>    x_ = Proxy(x)
>    y = ensure_eval(x_)
>    y_ = ensure_eval(y)
>    assert x is y
>    assert x is y_
> 
> This should always succeed, right? Well, what if x is itself a Proxy
> object? How does it know not to reevaluate it?
> 
> 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/GTCRUPQOFP63VA2T2N7BVBO6JKR3D7I6/
> Code of Conduct: http://python.org/psf/codeofconduct/

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

Reply via email to