Part 6 · 1 chapters · ~8 min
Evaluation Strategies
Eager and lazy evaluation, call by value, by reference, by sharing and by name, short-circuiting, thunks and memoised laziness, generators and iterators, streams and backpressure, infinite sequences, and the costs of laziness (space leaks, unpredictable timing).
7
Eager, lazy and passing
code
// pass by sharing (JS, Python, Java)
function f(acct) { acct.balance = 0; acct = { balance: 999 }; }
const a = { balance: 100 }; f(a); a.balance // 0: mutation visible, reassignment not
// laziness in an eager language: a generator yields on demand
function* ids() { let i = 0; while (true) yield `tr_${i++}`; } // infinite, fine
const first3 = [...take(ids(), 3)]; // only 3 computed
// lazy logging: pass a thunk so the message is built only if needed
logger.debug(() => `state=${JSON.stringify(bigObject)}`);
-- Haskell: lazy by default
take 5 (filter even [1..]) -- [2,4,6,8,10] from an infinite list
-- cost: foldl (+) 0 [1..10^7] builds 10 million unevaluated thunks (a space leak); foldl' is strictEVALUATION STRATEGIES
when arguments are computed, and how they are passed
swipe the figure sideways, or tap expand for full screen
1/4
eager
Most languages evaluate arguments before calling: log(expensive()) computes expensive() even if logging is off.
compute firstmost languages