Deferring work
Lazy evaluation delays a computation until its result is actually needed. A value starts as an unevaluated thunk and turns into a concrete result only when something forces it.
Where concurrency meets laziness
If two threads force the same thunk at the same time, you have a hidden shared mutable cell. Two risks appear:
- Duplicate work if both threads evaluate the thunk independently.
- A torn update if one thread reads the cell while another is writing it.
A safe lazy value uses a small atomic transition: the first thread that forces it computes the result, and the rest block briefly and then read the cached answer.
Streams from thunks
Laziness lets you build infinite structures, like a stream of natural numbers, because only the parts you touch are ever computed. Combined with immutability, a lazy stream is safe to share across consumers.
The danger
Pure laziness is safe, but a thunk that performs a side effect when forced makes timing observable, which breaks the illusion that order does not matter.
Key idea
Lazy values defer work until forced; under concurrency they must force exactly once and cache the result.