
A few points for clarity: Yes, I would expect each instance of delayed to result in a new delayed expression, without caching, except for multiple calls to that same delayed expression instance. Also, I suggested the colon : because unlike async/await, the following expression is NOT executed at the time delayed is executed. The only other ways to do this on Python I know of are def and lambda, both of which use colons to highlight this. As for what triggers execution? I think everything except being on the right side of an assignment. Even identity. So if a delayed expression would evaluate to None, then code that checks is None should return true. I think this is important to ensure that no code needs to be changed to support this feature. So for Chris: yes, rand is otherrand not because the delayed instances are the same, but because the value under them is the same, and the is should trigger evaluation. Otherwise code would need to be delayed aware. Finally as for the word delayed. Yes, it could be a symbol, or existing keyword, but I have no suggestions on that front. -Joseph
On Feb 17, 2017, at 6:21 AM, Chris Angelico <rosuav@gmail.com> wrote:
On Fri, Feb 17, 2017 at 10:10 PM, Steven D'Aprano <steve@pearwood.info> wrote:
the expression is executed and the delayed expression is replaced with the result. (Thus, the delayed expression is only every evaluated once).
That's easily done by having the "delayed" keyword cache each expression it sees, but that seems like a bad idea to me:
spam = delayed: get_random_string() eggs = delayed: get_random_string() # the same expression
spam.upper() # convert to a real value
assert spam == eggs # always true, as they are the same expression
Worse, suppose module a.py has:
spam = delayed: calculate(1)
and module b.py has:
eggs = delayed: calculate(1)
where a.calculate and b.calculate do completely different things. The result you get will depend on which happens to be evaluated first and cached, and would be a nightmare to debug. Truely spooky action-at-a- distance code.
My understanding is that a single 'delayed expression' will be evaluated at most once. It's more like this:
spam = delayed: get_random_string() eggs = spam
spam.upper() # At this point, the object becomes a real value assert spam is eggs # always true, as they are the same object
Two instances of "delayed:" will create two distinct delayed expressions.
The big question, though, is what triggers evaluation. AIUI, merely referencing the object doesn't (so "eggs = spam" won't force evaluation), but I'm not sure what does.
Do delayed-expressions have identities or only values? For example:
rand = delayed: random.randrange(10) otherrand = rand assert rand is otherrand # legal? randid = id(rand) # legal? print(rand) # force to concrete value assert any(rand is x for x in range(10)) # CPython int caching assert randid == id(rand) # now what?
Alternatively, once the value becomes concrete, the delayed-expression becomes a trampoline/proxy to the actual value. Its identity remains unchanged, but all attribute lookups would be passed on to the other object. That does mean a permanent performance penalty though - particularly if it's doing it all in Python code rather than some sort of quick C bouncer.
ChrisA _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/