On Sun, Jun 19, 2022 at 02:21:16AM +0100, Rob Cliffe via Python-ideas wrote:
Sorry, but I think all this talk about lazy evaluation is a big red herring: (1) Python is not Haskell or Dask.
Python is not Haskell, but we stole list comprehensions and pattern matching from it. Python steals concepts from many languages. And Python might not be Dask, but Dask is Python. https://www.dask.org/
(2) Lazy evaluation is something Python doesn't have,
Python has lazily evaluated sequences (potentially infinite sequences) via generators and iterators. We also have short-circuit evaluation, which is a form of lazy evaluation. There may be other examples as well. We may also get lazy importing soon: https://peps.python.org/pep-0690/ At last one of Python's direct competitors in the scientific community, R, has lazy evaluation built in.
and would be a HUGE amount of work for Chris (or anyone) to implement
I don't know how hard it is to implement lazy evaluation, but speaking with the confidence of the ignorant, I expect not that hard if you don't care too much about making it super efficient. A lazy expression, or thunk, is basically just a zero-argument function that the interpreter knows to call. If you don't care about getting Haskell levels of efficiency, that's probably pretty simple to implement. Rewriting Python from the ground up to be completely lazy like Haskell would be a huge amount of work. Adding some sort of optional and explicit laziness, like R and F# and other languages use, would possibly be little more work than just adding late-bound defaults. Maybe.
And in the unlikely event that Chris (or someone) DID implement it, I expect there would be a chorus of "No, no, that's not how (I think) it should work at all".
The idea is that you plan your feature's semantics before writing an implementation. Even if you plan to "write one to throw away", and do exploratory coding, you should still have at least a vague idea of the desired semantics before you write a single line of code.
(3) Late-bound defaults that are evaluated at function call time, as per PEP 671, give you an easy way of doing something that at present needs one of a number of workarounds (such as using sentinel values) all of which have their drawbacks or awkward points.
Yes, we've read the PEP thank you :-) Late-bound defaults also have their own drawbacks. It is not a question of whether this PEP has any advantages. It clearly does! The question is where the balance of pros versus cons falls.
(4) The guarantee that a late-bound default WILL be executed at function call time, can be useful, even essential (it could be time-dependent or it could depend on the values - default or otherwise - of other parameters whose values might be changed in the function body).
Okay. But a generalised lazy evaluation mechanism can be used to implement PEP 671 style evaluation. Let me see if I can give a good analogy... generalised lazy evaluation is like having a car that can drive anywhere there is a road, at any time of the day or night. Late-bound defaults is like having a car that can only drive to the local mall and back, and only on Thursdays. That's okay if you want to drive to the local mall on Thursdays, but if you could only have one option, which would be more useful?
Sure, I appreciate that there are times when you might want to defer the evaluation because it is expensive and might not be needed, but: (5) If you really want deferred evaluation of a parameter default, you can achieve that by explicitly evaluating it, *at the point you want it*, in the function body. Explicit is better than implicit.
That's not really how lazy evaluation works or why people want it. The point of lazy evaluation is that computations are transparently and automatically delayed until you actually need them. Lazy evaluation is kind of doing the same thing for CPUs as garbage collection does for memory. GC kinda sorta lets you pretend you have infinite memory (so long as you don't actually try to use it all at once...). Lazy evaluation kinda sorta lets you pretend your CPU is infinitely fast (so long as you don't try to actually do too much all at once). If you think about the differences between generators and lists, that might help. A generator isn't really like a list that you just evaluate a few lines later. Its a completely different way of thinking about code, and often (but not always) better.
IMO lazy evaluation IS a different, orthogonal proposal.
Late-bound defaults is a very small subset of lazy evaluation. But yes, lazy evaluation is a different, bigger concept. -- Steve