On Fri, Feb 17, 2017 at 12:24:53AM -0500, Joseph Hackman wrote: > I propose a keyword to mark an expression for delayed/lazy execution, for > the purposes of standardizing such behavior across the language. > > The proposed format is: > delayed: <expr> > i.e. log.info("info is %s", delayed: expensiveFunction())
Keywords are difficult: since by definition they are not backwards compatible, they make it hard for people to write version independent code, and will break people's code. Especially something like "delayed", I expect that there is lots of code that used "delayed" as a regular name. if status.delayed: ... A new keyword means it can't be back-ported to older versions, and will break code. > Unlike 'lambda' which returns a function (so the receiver must be > lambda-aware), delayed execution blocks are for all purposes values. The > first time the value (rather than location) is read, What counts as "reading" a value? Based on your example below, I can't tell if passing the object to *any* function is enough to trigger evaluation, or specifically print is the magic that makes it happen. > or any method on the delayed object is called, I don't think that can work -- it would have to be any attribute access, surely, because Python couldn't tell if the attribute was a method or not until it evaluated the lazy object. Consider: spam = delayed: complex_calculation() a = spam.thingy What's `a` at this point? Is is still some sort of lazy object, waiting to be evaluated? If so, how is Python supposed to know if its a method? result = a() > 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. I think it is better to stick to a more straight-forward, easily understood and debugged system based on object identity rather than expressions. > Ideally: > a = delayed: 1+2 > b = a > print(a) #adds 1 and 2, prints 3 > # a and b are now both just 3 > print(b) #just prints 3 That would work based on object identity too. By the way, that's probably not the best example, because the keyhole optimizer will likely have compiled 1+2 as just 3, so you're effectively writing: a = delayed: 3 At least, that's what I would want: I would argue strongly against lazy objects somehow defeating the keyhole optimizer. If I write: a = delayed: complex_calculation(1+2+3, 4.5/3, 'abcd'*3) what I hope will be compiled is: a = delayed: complex_calculation(6, 0.6428571428571429, 'abcdabcdabcd') same as it would be now (at least in CPython), apart from the "delayed:" keyword. a = delayed: complex_calculation(1+2+3, 4.5/3, 'abcd'*3) > Mechanically, this would be similar to the following: > > class Delayed(): > def __init__(self, func): > self.__func = func > self.__executed = False > self.__value = None > > def __str__(self): > if self.__executed: > return self.__value.__str__() > self.__value = self.__func() > self.__executed = True > return self.__value.__str__() So you're suggesting that calling str(delayed_object) is the one way to force evaluation? I have no idea what the following code is supposed to mean. > def function_print(value): > print('function_print') > print(value) > > def function_return_stuff(value): > print('function_return_stuff') > return value > > function_print(function_return_stuff('no_delay')) > > function_print(Delayed(lambda: function_return_stuff('delayed'))) > > delayed = Delayed(lambda: function_return_stuff('delayed_object')) > function_print(delayed) > function_print(delayed) -- Steve _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/