Skip to content

Lazy Evaluation

Prime #
955
Origin domain
Software Computing
Subdomain
programming languages → Software Computing
Aliases
Call by Need, Deferred Evaluation

Core Idea

Lazy evaluation is the discipline of doing work only when its result is actually demanded. Instead of computing every quantity the moment its inputs become available, lazy evaluation produces a deferred specification — a cheap promise that can deliver the value if asked — and lets that promise sit untouched, possibly forever, until something downstream actually consumes it. Four commitments define the move: decouple the moment a computation is specified from the moment it is performed; bind the timing of the work to demand from downstream rather than to the availability of inputs; record the result once produced so the work is not repeated; and tolerate the possibility that the work is never needed and so is never done at all.

The technical machinery in computing (call-by-need, thunks, memoisation, streams, generators) makes this exact and composable, but the underlying structural move is older and broader than any programming language. Across substrates the same three elements travel together: a specification of work that could be done, a trigger that pulls work into actual execution only on demand, and a commitment-deferral that buys time, preserves optionality, and avoids paying for work that turns out to be unnecessary. None of these elements is computational in essence; each names a relation between a potential action, a demand signal, and a moment of execution.

The structural dual is eager evaluation: compute everything up front, whether or not it is needed. The two form a clean trade-off pair, and seeing them as a pair is what makes the choice visible. Lazy evaluation pays a small bookkeeping cost — the deferred specification must be held and tracked — in exchange for potentially saving the much larger cost of work never demanded, plus the optionality of doing the work later with better information. Eager evaluation pays the full computation cost immediately to avoid bookkeeping and to have results ready the instant they are asked for. Neither dominates; which is right depends on how often the work is demanded, how costly the wait at force-time is, and how much the intervening information improves the deferred work.

How would you explain it like I'm…

Cook Only When Asked

Imagine you only cook a meal the moment someone is actually hungry and asks for it, instead of cooking every meal in the morning just in case. If nobody ever asks, you never cook it, and you save all that work. You also write down what you cooked so you don't have to make it twice.

Only When Needed

Lazy Evaluation is the rule of doing a piece of work only when its result is really needed, not the moment you could do it. Instead of computing something right away, you make a cheap little promise that says, 'I can give you this answer if you ask,' and you leave the promise alone — maybe forever — until something downstream actually wants the answer. Once you do the work, you save the result so you never repeat it. And if the answer is never asked for, the work simply never happens, which can save a lot of effort. The opposite habit is doing everything up front whether or not it's needed.

Work on Demand

Lazy Evaluation is the discipline of doing work only when its result is actually demanded. Instead of computing a value the moment its inputs are ready, you produce a cheap promise that can deliver the value if asked, and let it sit untouched, possibly forever, until something downstream consumes it. Four commitments define it: separate the moment work is specified from the moment it's performed; tie the timing to demand from downstream rather than to input availability; record the result once produced so it isn't repeated; and tolerate that the work might never be needed and so never done. Its opposite, eager evaluation, computes everything up front whether or not it's needed, and seeing them as a pair is what makes the choice visible. Lazy pays a small bookkeeping cost to hold the promise, in exchange for maybe skipping much larger unneeded work and gaining the option to act later with better information; neither always wins.

 

Lazy Evaluation is the discipline of doing work only when its result is actually demanded. Rather than computing every quantity the moment its inputs become available, it produces a deferred specification, a cheap promise that can deliver the value if asked, and lets that promise sit untouched, possibly forever, until something downstream consumes it. Four commitments define the move: decouple the moment a computation is specified from the moment it is performed; bind the timing of the work to demand from downstream rather than to input availability; record the result once produced so the work is not repeated; and tolerate the possibility that the work is never needed and so never done at all. The computing machinery, call-by-need, thunks, memoization, streams, generators, makes this exact and composable, but the underlying structural move is older and broader than any programming language. Across substrates the same three elements travel together: a specification of work that could be done, a trigger that pulls work into actual execution only on demand, and a commitment-deferral that buys time, preserves optionality, and avoids paying for work that turns out to be unnecessary, none of which is computational in essence. The structural dual is eager evaluation, which computes everything up front regardless of need; the two form a clean trade-off pair, and seeing them as a pair makes the choice visible. Lazy pays a small bookkeeping cost, the deferred specification must be held and tracked, in exchange for potentially saving the much larger cost of work never demanded plus the optionality of doing the work later with better information. Eager pays full computation cost immediately to avoid bookkeeping and have results ready instantly. Neither dominates; the right choice depends on how often the work is demanded, how costly waiting at force-time is, and how much intervening information improves the deferred work.

Structural Signature

a deferred specification of work that could be donea separation of specify-time from execute-timea demand trigger that pulls work into executionforce-time execution informed by demand contextan optional never-executed paththe bookkeeping-cost-versus-saved-work trade-off against eager evaluation

A discipline is lazy evaluation when the following hold:

  • A deferred specification. A cheap stand-in — thunk, recipe, query plan, option, operon — that could deliver a value but holds it unproduced, rather than the computed result itself.
  • Specify–execute decoupling. The moment work is specified is split from the moment it is performed; the two travel separately instead of collapsing into one.
  • A demand trigger. Execution is bound to a downstream pull — a result iterator, a kanban card, a customer order, an inducer molecule, an exercise event — not to the availability of inputs.
  • Force-time execution. When demand fires, the work runs, informed by whatever context arrived between specification and force; results are recorded so the work is not repeated.
  • An optional non-execution path. Demand may never arrive, in which case the work is never done at all — the source of lazy evaluation's largest savings.
  • The eager trade-off. Deferral pays a holding/bookkeeping cost (and force-time latency, memory for held specifications) to buy saved work on unneeded results plus better-informed work on needed ones; its dual, eager evaluation, pays full compute up front to avoid bookkeeping. Neither dominates.

These compose into one move: hold a cheap specification, bind its execution to downstream demand, and let unneeded work go undone while needed work runs with later, better information.

What It Is Not

  • Not caching. Caching stores a result already computed to avoid recomputing it; lazy evaluation avoids computing in the first place until demand arrives. Memoisation is a caching add-on to laziness, but the core laziness move is non-execution, not result reuse.
  • Not future_or_promise. A future reifies a result that a producer is committed to supply (work often already running); lazy evaluation defers the computation itself, which may never run at all if demand never comes. Pull-on-demand versus producer-driven fulfillment.
  • Not optionality. Optionality is a held right to act later; lazy evaluation is a mechanism that defers execution to demand. Laziness preserves optionality as a side benefit, but it is the deferral machinery, not the right.
  • Not postponement. Postponement delays a committing step to a later, better-informed moment as a deliberate strategy; lazy evaluation binds execution to downstream demand specifically, and tolerates the work never happening — a narrower, demand-triggered discipline.
  • Not recursion. Recursion is self-reference in a definition; lazy evaluation is demand-driven deferral of work. They co-occur (lazy infinite streams) but are orthogonal — most recursion is eager, most laziness non-recursive.
  • Common misclassification. Calling any "do it later" laziness. Catch it by checking the demand trigger and the non-execution path: is execution bound to a downstream pull, and can the work be never done at all? If the work is merely scheduled to run later regardless, it is deferral or batching, not lazy evaluation.

Broad Use

The same demand-pulled deferral pattern surfaces across many substrates. In programming languages and systems it is call-by-need, lazy sequences, generators, promises and futures, and lazy loading of attributes and assets. In build systems and dependency engines the build graph specifies possible work and demand prunes it to actual work, rebuilding a target only when its output is required and its inputs have changed. In databases and query planners it appears as cursors, streaming results, refresh-on-demand materialised views, and deferred constraint checking. In operations and manufacturing it is Just-In-Time production — make the part when the next station pulls for it, not before — and the pull system generally, with the kanban card as the demand trigger. In supply chain and logistics it is drop-shipping, print-on-demand, build-to-order, and late differentiation, where the SKU-distinguishing step is postponed until a customer order arrives.

In decision-making and strategy it is the deliberate deferral of reversible-cost decisions until the information needed to make them is in hand, and real-options thinking that preserves the right (not obligation) to act later. In finance and procurement it is pay-on-delivery, revolving credit drawn only when needed, and capital deployed only when an investment thesis fires. In biology it is inducible gene expression — the lac operon synthesising its protein only when lactose arrives — and on-demand cytokine production in immune signalling. In law it is the ripeness doctrine: courts defer rulings on hypothetical matters until an actual controversy arises. In each case the template is the same: separate what could be done from when it is done, bind execution to demand, and pay the holding cost of the specification in exchange for the savings of never doing unneeded work plus the lift of doing demanded work with later information.

Clarity

Naming this discipline turns a fuzzy "we'll get to it later" intuition into a precise design question with four named parts. What is the deferred specification — the cheap thing being held in lieu of the result? What is the trigger — the demand signal that promotes the specification to actual work? What does the deferral buy — saved cost when the work is unneeded, better-informed work when it is needed, optionality, the chance to parallelise? And what does the deferral cost — the bookkeeping to hold and track the specification, the latency at the moment of forcing, the memory consumed by held specifications, and the debugging difficulty when a failure surfaces at force-time, far from where the deferral was created?

Once that frame is in place, decisions that look unrelated reveal themselves as the same trade-off. "Build to stock or build to order," "precompute the statistics or compute them on query," "decide now or wait for the deal to break the other way," "synthesise this protein continuously or only on demand," and "render this page on the server or in the browser when scrolled into view" are all instances of choosing where to sit on the lazy-eager axis. The clarifying force is that the vocabulary makes the held specification, the trigger, and the two ledgers of cost explicit — so the choice can be defended on its structure rather than settled by habit or local convention.

Manages Complexity

Lazy evaluation collapses the worst-case work to be done into the work actually demanded, which is often a tiny fraction of the worst case. A query planner that materialises only the columns a query touches, a build system that rebuilds only changed paths, a factory that produces only sold-through variants, a real-options portfolio that defers commitments until the bad scenarios are eliminated — each reduces realised cost from "everything that could conceivably be needed" to "what was actually asked for." This is a complexity reduction in the most direct sense: the system never has to reason about, schedule, or store the vast space of unrequested work.

It also moves cost across time in a way that buys information. The work performed at force-time is informed by whatever demand context arrived between specification and execution, and that informational lift is frequently what makes the deferred work better than its eager equivalent — postponed product differentiation matches the actual demand mix, and a deferred legal ruling fits the actual factual record. The failure modes are equally structural and worth naming: deferral loses when the bookkeeping cost is large relative to the work itself (eager beats lazy on small jobs), when the force-time execution lands in a context that cannot tolerate the latency (the wait is unacceptable), or when held specifications accumulate faster than they are consumed and the system leaks resources holding promises it will never force.

Abstract Reasoning

Lazy evaluation trains a reasoner to distinguish the specification of work from its execution and to let those two travel separately rather than collapsing them into a single moment. It teaches the reasoner to identify the demand signal that should pull a specification into execution, and to ask the decisive question about any deferred work: might it never be needed — in which case deferral is a near-pure win, modulo bookkeeping — or will it eventually be needed, in which case deferral pays off only if the intervening wait improves the work or its inputs? It surfaces the dual to eager evaluation explicitly, prompting the reasoner to track which costs are paid up front, which are paid on demand, and what information accrues in between.

The portable abstraction is a role-set that ports across substrates: the deferred specification (the thunk, recipe, query plan, gene, or option held but not executed), the demand trigger (the downstream pull, the kanban signal, the result iterator, the inducer molecule, the exercise event), the force-time execution (the work done at the moment demand fires, informed by demand-time context), the optional non-execution path (where demand never arrives and the work is never done), the bookkeeping cost (what the holding infrastructure consumes), and the information lift (what the wait between specification and force buys). A reasoner equipped with this role-set can look at JIT manufacturing, demand-paged virtual memory, a real-options portfolio, "wait for ripeness," and inducible enzyme synthesis and recognize them as one structural move on different substrates.

Knowledge Transfer

The structure ports as an intervention menu, and the menu is what makes the transfer more than analogy. Take Toyota's Just-In-Time manufacturing as a worked mapping. The deferred specification is the production recipe for a part; the demand trigger is the downstream station's kanban card pulling for it; the force-time execution is the actual production run, sized and scheduled to the pull; the optional non-execution path is the case where demand never arrives and no work-in-process accumulates; the bookkeeping cost is the kanban infrastructure and signalling discipline; and the information gained while waiting is up-to-the-minute knowledge of the actual demand mix and defect rate. Every element of the computing pattern has a precise operations counterpart, and the design moves — make the specification cheap, install a reliable demand signal, set a force-time latency budget, manage the holding cost — transfer with it.

The same template maps cleanly onto query planning (specification = query plan, trigger = result iteration, force-time = scan and filter, optional = early termination, information = current table statistics), onto real options (specification = the option, trigger = the exercise event, force-time = pay strike and take asset, optional = let it expire, information = updated market state), onto inducible enzyme synthesis (specification = the operon, trigger = substrate presence, force-time = transcription and translation, optional = no substrate and no protein, information = the ambient nutrient signal), and onto courts deferring rulings until ripeness. What transfers in every case is the diagnostic-and-intervention pair: identify the eager waste, design a cheap deferred specification, install the demand signal, set the force-time latency budget, manage the bookkeeping, and decide deliberately which failures should fire at specification-time versus force-time. A practitioner who has internalized this in one domain arrives in the next already knowing where to look for unnecessary up-front work and how to convert it into demand-pulled work — the structural skeleton ports with minimal translation even though the term itself carries a computing flavour that may need restating in the receiving field's vocabulary.

Examples

Formal/abstract

Take a lazy infinite stream in a call-by-need language — the canonical fibs = 0 : 1 : zipWith (+) fibs (tail fibs) — as the rigorous instance. The deferred specification is a thunk: each stream cell holds not a number but an unevaluated promise to compute one. The specify–execute decoupling is total: the program describes an infinite sequence in one line, yet nothing is computed at definition time. The demand trigger is consumption — take 10 fibs pulls exactly ten values; the eleventh thunk is never forced. Force-time execution runs each addition only when demanded, and crucially memoisation records the result so that fibs !! 30, which references earlier cells many times, computes each Fibonacci number once rather than re-descending the recursion exponentially. The optional non-execution path is the whole infinite tail past the tenth element: specified, never executed, costing nothing. The eager trade-off is exact and visible — eager evaluation of an infinite list would not terminate at all, so here laziness is not an optimisation but an enabling condition; the price is the bookkeeping of held thunks and the risk of a space leak if a long chain of unforced thunks accumulates unconsumed. The intervention the prime sharpens: when a lazy program leaks memory, the diagnosis is "held specifications accumulating faster than demand consumes them," and the fix is to force strictly at a chosen point — deliberately moving a computation back toward the eager end of the axis.

Mapped back: The Fibonacci stream instantiates every role — thunks as deferred specifications, specify/execute decoupling, demand-pulled forcing, memoised force-time execution, an unexecuted infinite tail, and the thunk-bookkeeping cost — showing deferral converting an impossible eager computation into a tractable demand-pulled one.

Applied/industry

Consider Toyota's Just-In-Time manufacturing and inducible gene expression (the lac operon) as two applied instances of the identical demand-pulled skeleton. On the factory floor the deferred specification is the production recipe for a part; the demand trigger is the downstream station's kanban card pulling for it; force-time execution is the actual production run, sized to the pull and informed by the current demand mix and defect rate (the prime's information lift); the optional non-execution path is the variant never ordered, for which no work-in-process ever accumulates; and the bookkeeping cost is the kanban signalling discipline. The structural payoff is the prime's central one: realised work collapses from "every variant that could conceivably sell" to "what was actually pulled." The lac operon runs the same pattern in a cell: the deferred specification is the operon's genetic recipe for lactose-metabolising enzymes; the demand trigger is the presence of lactose (via the inducer); force-time execution is transcription and translation; and the optional non-execution path is the common case where no lactose is present and the protein is simply never synthesised — saving the cell the metabolic cost of producing an enzyme it cannot use. The shared intervention across both: identify the eager waste (overproduction, constitutive synthesis), install a reliable demand signal, and let unneeded work go undone.

Mapped back: JIT manufacturing and the lac operon both run the prime end-to-end — a cheap held specification, a downstream demand trigger, demand-informed force-time execution, and a large savings on the never-demanded path — confirming the deferral skeleton transfers from code to the shop floor to the cell, with only the substrate of the "thunk" changing.

Structural Tensions

T1 — Deferral Savings versus Bookkeeping Cost. Laziness saves the work never demanded but pays a holding cost to keep and track each deferred specification; eager evaluation pays full compute up front to avoid that bookkeeping. The tension is scalar: deferral wins big when the saved work is large relative to the holding cost, loses when the job is small. The failure mode is deferring trivial computations whose thunk-management overhead exceeds the work itself, making lazy slower than eager. Diagnostic: compare the cost of holding-and-tracking the specification against the cost of just doing the work; on small jobs, eager dominates.

T2 — Specify-Time versus Force-Time Latency. Decoupling specification from execution moves cost off the up-front path and onto the moment demand fires — but that moment may not tolerate the wait. The tension is temporal: deferral smooths or eliminates up-front cost at the price of latency precisely when the result is finally needed. The failure mode is a force-time execution landing in a latency-critical context (a user-facing request forcing a deep thunk chain), turning saved up-front work into an unacceptable stall. Diagnostic: ask whether the context at force-time can absorb the deferred work's latency; if not, pre-force or move toward eager.

T3 — Held Specification versus Resource Leak. A deferred specification sits cheaply until forced, but specifications can accumulate faster than demand consumes them. The tension is that "cheap to hold" is per-item, while the population of unforced specifications can grow unbounded. The failure mode is the space leak — a long chain of unforced thunks (or unfilled orders, unexercised options, uncollected promises) consuming memory the system holds against demand that never comes fast enough. Diagnostic: ask whether held specifications are consumed at least as fast as they are created; if they accumulate, force strictly at a chosen point to drain them.

T4 — Never-Executed Savings versus Eventually-Needed Work. Deferral is a near-pure win when the work is never demanded, but only pays on eventually-needed work if the intervening wait improves it. The tension is that these two cases call for opposite reasoning. The failure mode is deferring work that will certainly be needed and gains nothing from waiting — paying the bookkeeping and force-time latency for a result eager evaluation would have had ready, with no offsetting information lift. Diagnostic: ask whether the deferred work might never be needed (defer freely) or will surely be needed (defer only if the wait improves inputs or context).

T5 — Information Lift versus Stale Specification. Force-time execution is informed by context that arrived after specification — the source of laziness's informational advantage. The tension is sign-flipped: the same gap between specify-time and force-time that improves demand-matched work can also let the specification itself go stale, capturing assumptions no longer valid when forced. The failure mode is forcing a deferred specification whose captured inputs or environment have changed underneath it — a thunk closing over mutated state, a build recipe whose dependencies shifted. Diagnostic: ask whether the specification's captured context can change between specify-time and force-time, and whether forcing it then yields the right answer or a stale one.

T6 — Failure at Specification-Time versus Force-Time. Eager evaluation surfaces errors where the work is written; laziness defers them to wherever the result is forced, far from the originating code. The tension is that deferral relocates not just computation but failure. The failure mode is a bug or exception erupting at force-time, deep in a consumer, with no obvious link back to the deferral site that created it — making debugging hard precisely because cause and symptom are separated in time and place. Diagnostic: decide deliberately which failures should fire eagerly at specification-time (validation, type errors) versus lazily at force-time, rather than letting all errors drift to the consumer.

Structural–Framed Character

Lazy Evaluation sits on the structural side of the structural–framed spectrummixed-structural, aggregate 0.3. The demand-pulled deferral skeleton is genuinely substrate-independent, but the term originates in programming languages and carries that flavour when transferred, which lifts three diagnostics to the half-mark.

Walk them. Vocabulary travels (0.5): the separate-specification-from-execution-and-bind-to-demand move is statable plainly and recurs in JIT manufacturing, inducible gene expression, and the legal ripeness doctrine, but the term — and "thunk," "call-by-need," "memoisation," "force" — drags a CS flavour along that needs restating in the receiving field. Institutional origin (0.5): the construct is coined in programming-language theory, a real disciplinary origin, though the underlying pull-on-demand pattern genuinely predates it in operations and biology, which holds this to 0.5. Import vs. recognize (0.5): calling JIT or the lac operon "lazy evaluation" half-imports the deferred-specification/demand-trigger framing and half-recognizes a demand-pulled deferral already there. The other two read zero. No evaluative weight (0): laziness is neither good nor bad — eager and lazy form a neutral trade-off pair, and which wins depends on the cost structure, not on approval. Not human-practice-bound (0): the lac operon synthesises its enzymes only when lactose arrives in a purely biological substrate, with no human practice required for the demand-pulled deferral to operate. Three half-points against two zeros land exactly at the 0.3 aggregate and mixed-structural label — a clean structural skeleton wearing a programming-language name.

Substrate Independence

Lazy Evaluation is a strongly substrate-independent prime — composite 4 / 5 on the substrate-independence scale. Its domain breadth is maximal: the demand-pulled deferral skeleton — hold a cheap specification, bind execution to downstream demand, let unneeded work go undone — appears as call-by-need, thunks, and generators in programming languages; as demand-pruned rebuilding in build systems; as cursors and refresh-on-demand views in databases; as Just-In-Time production and the kanban pull system in manufacturing; as drop-shipping and late differentiation in supply chains; as real-options deferral in strategy; as draw-only-when-needed credit in finance; as inducible gene expression (the lac operon synthesising enzymes only when lactose arrives) in biology; and as the ripeness doctrine in law. The structural abstraction is high: the same role-set — deferred specification, demand trigger, force-time execution, optional non-execution path, bookkeeping cost, information lift — and the same lazy-versus-eager trade-off carry across every instance. The transfer evidence is concrete and runs as a portable intervention menu: identify the eager waste, design a cheap deferred specification, install the demand signal, set a force-time latency budget, manage the holding cost. The lac operon, deferring synthesis until substrate presence with no human practice, anchors the pattern firmly in a biological substrate. What caps it at 4 is a programming-language vocabulary accent — "thunk," "call-by-need," "memoisation," "force" — that drags a CS flavour along and needs restating in the receiving field. Maximal spread and strong transfer with a light CS accent give a confident 4.

  • Composite substrate independence — 4 / 5
  • Domain breadth — 5 / 5
  • Structural abstraction — 4 / 5
  • Transfer evidence — 4 / 5

Relationships to Other Primes

One-hop neighborhood: parents above, mutual partners to the right, children below.Lazy Evaluationsubsumption: PostponementPostponement

Parents (1) — more general patterns this builds on

  • Lazy Evaluation is a kind of Postponement

    Genus-species, asserted by both files. lazy_evaluation's What-It-Is-Not: "Postponement delays a committing step to a later, better-informed moment... lazy evaluation binds execution to downstream demand specifically... a narrower, demand-triggered discipline." postponement's frontmatter lists "late binding/lazy eval" as an instance and its own What-It-Is-Not does NOT sever lazy_evaluation. Direction: lazy_evaluation is the narrower demand-triggered species of disciplined deferral. postponement is a real candidate slug. Medium (not high) because lazy_evaluation's optional never-execute path is a genuine differentiator absent from postponement's latest-responsible-moment binding. NOT a reparent to allocation (0.879 nearest, unrelated). Distinct from caching/future_or_promise/optionality per the file.

Path to root: Lazy EvaluationPostponementOptionalityUncertainty

Neighborhood in Abstraction Space

Lazy Evaluation sits in a sparse region of abstraction space (96th percentile for distinctiveness): few abstractions share its structure, so a faithful description tends to retrieve it precisely rather than landing on a neighbor.

Family — Formal Methods & Idealized Models (31 primes)

Nearest neighbors

Computed from structural-signature embeddings · 2026-06-14

Not to Be Confused With

The most consequential confusion is with caching, and the two are genuinely entangled because real lazy systems usually include a cache (memoisation records a forced result so the work is not repeated). But the core moves are different and separable. Caching is about not recomputing work already done: it stores a result and serves the stored copy on later requests, trading memory for avoided recomputation. Lazy evaluation is about not doing work until it is demanded — and, crucially, possibly never doing it. The defining win of laziness is the non-execution path: work that is specified but never demanded is never performed at all. Caching has no such path; it presupposes the work was done at least once, then preserved. So a lazy value that is never forced costs only its held specification (laziness's gain) and is never cached because it never ran; a cached value, by contrast, exists precisely because the computation already happened. Conflating them leads to expecting laziness to "remember" results it never computed, or expecting a cache to spare you a computation you have not yet triggered.

It is also routinely confused with future_or_promise, since both reify "a value that isn't here yet." The distinguishing axis is who drives the work and whether it is already underway. A future is a handle on a result that a producer is committed to supply; the underlying computation is typically already running (or scheduled to run) independently of whether any consumer is waiting, and the future merely lets consumers attach. Lazy evaluation is pull-driven: the computation does not start until a downstream consumer demands the value, and if no demand ever comes the work simply never happens. The signatures diverge sharply — a future's side effects proceed whether or not you await it, whereas a lazy thunk that is never forced produces no side effects at all. Treating a lazy value as a future (assuming its work is already in flight) or a future as lazy (assuming it is safe to ignore because it "won't run until needed") both misjudge when the work actually occurs.

A third confusion is with optionality. Both relate to "keeping things open," and laziness does preserve optionality (deferring work lets you act later with better information). But optionality is a right — the entitlement to choose whether and how to act later, valuable in itself — while lazy evaluation is a mechanism that binds execution to demand. One is a property of a decision situation; the other is an implementation discipline for computation. A system can have optionality with no laziness (it holds open choices but computes everything eagerly) and laziness with no meaningful optionality (it defers work purely for efficiency, with no decision riding on the delay). Reading laziness as optionality overstates it — not every deferred computation embodies a valuable open choice.

For a practitioner the through-line is when, and whether, the work runs. Caching presupposes the work ran and reuses it; futures usually have the work running already, producer-driven; optionality is about a decision right, not computation; and lazy evaluation alone binds execution to downstream demand and admits that the work may never run at all. Knowing which is in play tells you where side effects occur, where failures surface, and what you are actually saving.

Solution Archetypes

No catalogued solution archetypes reference this prime yet.