There seems to be a misunderstanding about how the existing short-circuit operators, and
& or
in Python. 1st short-circuit is a form of lazy evaluation, e.g. see Short-circuit evaluation - Wikipedia. 2nd wrapping the operators cause their laziness to be lost. An example in this thread suggested by others is a trace_calc
wrapper, but as demonstrated below this doesn’t work for and
& or
:
def trace_calc(calc, *args, **kwargs):
result = calc(*args, **kwargs)
print(f'{result}, {args}, {kwargs}')
return result
If we define an or
expression that has side effects:
a = True
def b():
print('Evaluate b')
return True
print(a or b())
It prints “True” and importantly doesn’t print “Evaluate b” because b
isn’t evaluated. However, if the or
expression is wrapped in trace_calc
the laziness id lost:
print(trace_calc(lambda l, r: l or r, a, b()))
Prints “Evaluating b”, “True, (True, True), {}”, and “Tue”, importantly “Evaluating b” which shows that the evaluation has been changed by the wrapping.
Therefore in exisiting Python you cannot write a general expression wrapper that does not change the evaluation.
The proposed Lazy
does not have this problem.
def my_or(l, r: Lazy):
if l:
return True
return r()
print(my_or(a, Lazy(lambda: b()))) # After compiler re-write
Prints “True” and not “Evaluate b”, showing that it behaves like the built in or
. When wrapped in trace_calc
:
print(trace_calc(my_or, a, Lazy(lambda: b())))
Which prints “True” and not “Evaluate b”, which shows that Lazy
variables are passed on unevaluated.
Note the my_or
example was just an example, it is not proposed that and
nor or
be changed.