Skip to content

Demand Triggered Deferred Evaluation

Represent optional or path-dependent work as a suspended unit, realize only the dependency closure demanded now, and make result sharing, side effects, failure timing, cancellation, lifetime, and first-use latency explicit.

Overview

Demand-Triggered Deferred Evaluation is the general solution pattern behind lazy evaluation: represent work before executing it, and pay for it only when a real consumer needs its result. The pattern is broader than one language evaluation rule. It appears in lazy streams, deferred initialization, query late materialization, target-oriented builds, demand paging, copy-on-write, and on-demand reports.

The archetype is not simply ‘wait.’ A sound design must say what counts as demand, which dependencies are necessary, what state the work occupies before and during realization, whether concurrent demand shares one execution, how side effects and failures behave, when captured inputs expire, and when the latency cost justifies forcing work early. Without those contracts, laziness becomes hidden execution, late surprises, and unbounded retained state.

Why this is a distinct archetype

The accepted catalog already contains close neighbors, but none owns the complete demand-gated realization loop. Precomputation / Prefetching does likely work before demand. Strategic Caching stores an already realized result. Dynamic Subproblem Reuse avoids recomputing overlapping subproblems. Inversion of Control changes who initiates behavior. Option Preservation delays commitment. Threshold-Based Activation waits for a measured condition. Progressive Disclosure controls when information is shown.

This archetype starts one step earlier: the work itself remains a suspended possibility. Actual demand selects a minimal dependency closure, activates it, and changes its lifecycle. That creates a distinctive set of obligations around first-use latency, duplicate suppression, input lifetime, deferred failure, side-effect timing, result sharing, cancellation, and strictness escape.

Problem pattern

A system eagerly computes, loads, initializes, copies, traverses, or generates outputs before it knows whether any downstream path will use them. Optional branches, large sequences, expensive dependencies, remote data, and rarely used features consume time, memory, bandwidth, energy, and failure surface even when abandoned. Ad hoc laziness can reverse the waste but hide execution timing, move failures far from construction, retain stale inputs, duplicate concurrent work, trigger side effects late, and create first-use latency cliffs. The problem is therefore not merely “do less work”; it is to make nonexecution, later realization, and result publication part of an explicit contract.

The usual anti-pattern has two stages. First, eager work becomes the default because it is simple to reason about locally. Later, teams add ad hoc lazy loaders, promises, or conditional branches to recover performance. The system then pays a different price: timing is hidden, failures migrate to distant call sites, and one innocent property read can issue a network request. The archetype replaces both extremes with an explicit lifecycle and measurable budget.

Structural intervention

Replace eager execution with an explicit suspended-work representation. Define the legitimate demand boundary, map dependencies, test semantic need, capture valid inputs, and activate only the minimum required closure when demand arrives. Coordinate duplicate demand, isolate effects, publish results under a sharing policy, expose failures and provenance, support cancellation and invalidation, and continuously tune the latency-waste tradeoff with an eager escape hatch.

Ordered action logic

  1. Inventory eager work and measure how often each result is actually consumed.
  2. Select units whose avoided-work value plausibly exceeds added latency, retention, and coordination cost.
  3. Define the deferred unit, its inputs, dependencies, output contract, side-effect profile, and owner.
  4. Specify the demand boundary and need predicate that distinguish actual use from prediction or incidental inspection.
  5. Represent the unit in an explicit suspended state with valid capture and lifecycle semantics.
  6. On demand, determine the smallest dependency closure that must be realized for this request.
  7. Check authorization, versions, resource availability, cancellation state, and safety constraints before activation.
  8. Coalesce equivalent concurrent demand or deliberately allow independent realization according to policy.
  9. Execute the realization path, isolate or explicitly commit side effects, validate the output, and record provenance.
  10. Publish, memoize, share, stream, or discard the result according to the result-sharing and lifetime policy.
  11. Propagate failures, retries, cancellation, invalidation, and cleanup with explicit semantics.
  12. Trace demand-to-realization behavior and compare avoided work, first-use latency, retention, duplicate execution, and error timing with the eager baseline.
  13. Force or prefetch selected units eagerly when evidence shows that strict laziness violates service, safety, deadline, or resource-lifetime invariants.

Required components

The required components form one control loop from suspension through realization and review.

Deferred Work Unit

Required component; type: object_or_artifact. Defines the computation, retrieval, transformation, initialization, or bounded action that may remain unrealized until its value is requested.

The unit must expose inputs, dependencies, estimated cost, purity or side-effect status, expected output, and ownership. If the work cannot be bounded or safely suspended, laziness becomes hidden backlog rather than controlled deferral.

Demand Boundary

Required component; type: boundary. States exactly what event counts as a legitimate demand for the deferred result and which apparent uses do not.

Demand may be an actual value read, a requested target, a visible interface reveal, a missing page fault, or a downstream dependency. Metrics, logging, serialization, debugging, and speculative inspection must be classified because they can accidentally force realization.

Demand Signal

Required component; type: feedback_signal. Carries the concrete request that crosses the demand boundary and identifies the requested value, scope, caller, and urgency.

Reuse the indexed component. In this archetype the signal is not a forecast of future demand; it is evidence that the result is needed now. The signal should be attributable and deduplicable where concurrent request coalescing is required.

Deferred Dependency Map

Required component; type: object_or_artifact. Shows which deferred units depend on which inputs or other units so only the transitive closure required by the present demand is realized.

This archetype-specific map records dependencies among deferred units and their demand-relevant inputs. It enables branch pruning, cycle detection, invalidation, scheduling, and explanation of why work ran. Hidden dependencies defeat demand-based execution because the system cannot know what is actually necessary.

Need Predicate

Required component; type: criterion. Determines whether the requested result is semantically necessary, already available, safely approximable, or avoidable for the current path.

The predicate prevents every contact with a deferred object from becoming demand. It may test branch selection, field access, target reachability, cache validity, authorization, or downstream consumption.

Suspended Evaluation State

Required component; type: state. Represents deferred work before realization, including captured inputs, lifecycle state, ownership, and whether evaluation is not started, running, completed, failed, cancelled, or invalidated.

A suspended state must not masquerade as a completed value. Explicit states prevent duplicate execution, ambiguous failures, use-after-close errors, and races between demand, cancellation, and invalidation.

Activation Rule

Required component; type: decision_rule. Converts a valid demand signal into permission to realize the deferred work, subject to scope, authorization, resource, and safety constraints.

Reuse the indexed component. The rule should distinguish demand-triggered activation from forecast-triggered precomputation and threshold-triggered response. It must also define whether demand blocks, returns a future, degrades, or fails fast.

Realization Path

Required component; type: transformation. Executes the minimum dependency closure needed to turn the suspended unit into a result and records the transition.

The path specifies ordering, resource acquisition, retries, partial progress, output validation, cleanup, and publication. Realization should be deterministic or explicitly nondeterministic and should not silently broaden beyond the requested scope.

Result-Sharing Policy

Required component; type: decision_rule. Determines whether a realized result is returned only to the triggering demand, shared with concurrent demanders, memoized for later reuse, or recomputed each time.

This component separates call-by-name, call-by-need, single-flight, and cached forms. Sharing increases reuse but introduces freshness, scope, tenancy, authorization, memory, and invalidation obligations.

Single-Flight and Duplicate-Suppression Rule

Required component; type: constraint. Prevents simultaneous demanders from realizing the same expensive unit multiple times when one in-flight realization can safely satisfy them.

The rule needs a stable identity key, join policy, timeout, cancellation semantics, failure fan-out behavior, and isolation boundary. Coalescing unrelated requests can leak data or create head-of-line blocking.

Side-Effect Boundary

Required component; type: boundary. Separates value production that may be safely delayed or repeated from externally visible effects whose timing, order, or multiplicity matters.

Reuse the indexed component. Side effects should normally be isolated, made idempotent, or placed behind an explicit commit step. Deferring an effect can change business, safety, legal, or user-visible behavior even when the returned value is correct.

Failure and Exception Semantics

Required component; type: decision_rule. Defines when errors are raised, how they are attributed to the deferred unit, whether failures are memoized, and what later demand observes.

Laziness moves failures away from construction time and toward first use. The design must preserve causal context, stack or provenance information, retry policy, partial-result handling, and whether one failed realization poisons future demand.

Cancellation and Abandonment Rule

Required component; type: decision_rule. Stops or discards deferred or in-flight work when the original demand disappears, becomes obsolete, or exceeds its budget.

Cancellation must define shared-demand behavior, cleanup, compensation for side effects, resource release, and whether partial progress can be resumed. Abandonment should not strand locks, leases, temporary files, or unresolved promises.

Latency and Waste Budget

Required component; type: constraint. Balances avoided unnecessary work against first-demand delay, retained state, coordination overhead, and the cost of late failure.

The budget should measure avoided work, realization latency, tail latency, duplicate evaluation, retained memory, stale results, cancellation waste, and user or downstream consequences. Laziness is not automatically efficient when demand probability is high or startup cost is dominant.

Demand and Realization Trace

Required component; type: feedback_signal. Records which demand forced which deferred units, what dependency path ran, how long it took, and what result, failure, cancellation, or reuse event followed.

The trace makes hidden timing visible. It supports debugging, performance tuning, security review, demand-probability estimation, dead-work identification, and comparison with eager or prefetched alternatives.

Input-Lifetime and Capture Rule

Required component; type: constraint. Ensures every captured input, handle, credential, snapshot, and environment assumption remains valid until realization or is safely reacquired.

Deferred closures can retain large object graphs or outlive files, sessions, transactions, permissions, and temporal assumptions. Capture should be minimal, explicit, versioned where needed, and released after completion or cancellation.

Strictness Escape Hatch

Required component; type: decision_rule. Allows selected work to be forced eagerly when bounded latency, deterministic failure timing, resource release, safety, or observability is more important than avoiding work.

A mature lazy design needs a deliberate path back to eager evaluation. The escape hatch should be scoped, measurable, reversible, and justified rather than used as an ad hoc workaround for every performance surprise.

Optional components

These components become necessary only when results are shared, inputs mutate, dependencies recurse, authorization changes, or service guarantees are strict.

Memoized Result Store

Optional component; type: resource. Retains a completed result keyed by the deferred unit and relevant input state so later demand can reuse it.

Use when results are reusable and stable enough to justify storage. The store imports cache concerns such as identity, capacity, freshness, eviction, isolation, and invalidation; it is optional because pure call-by-name recomputes on each demand.

Invalidation Rule

Optional component; type: decision_rule. Determines when a suspended or memoized result no longer corresponds to current inputs, permissions, versions, or policy.

Reuse the indexed component. Invalidation may reset the unit to suspended state, force recomputation, reject use, or route to a refreshed dependency closure. Broad invalidation can erase the expected benefit of laziness.

Version Token

Optional component; type: state. Binds captured inputs and realized results to a version, epoch, snapshot, or dependency frontier.

Reuse the indexed component when mutable inputs or distributed state make identity-by-object insufficient. Version tokens support safe memoization, invalidation, replay, and explanation of stale results.

Cycle and Nontermination Guard

Optional component; type: constraint. Detects recursive demand cycles, unproductive infinite expansion, and dependency chains whose realization cannot complete within a declared bound.

Lazy structures can represent infinite objects safely only when demand consumes a finite productive prefix. Guards distinguish productive recursion from cycles that repeatedly demand their own unresolved value.

Authorization Revalidation Rule

Optional component; type: decision_rule. Rechecks whether the current demander may realize or receive the deferred result rather than relying only on authority captured at construction time.

Permissions may expire or differ between the creator and the eventual demander. Revalidation is essential when deferred work reads protected data, performs billable actions, or shares results across tenants or roles.

Service-Level Objective

Optional component; type: metric. States acceptable first-demand latency, completion reliability, duplicate-execution rate, cancellation cleanup time, and result freshness.

Reuse the indexed component for production-critical lazy paths. Separate user-perceived first-use latency from background resource savings so optimization does not hide a degraded experience.

Prefetch or Eager-Exception Rule

Optional component; type: decision_rule. Permits selected deferred units to be realized early when demand probability, deadline, safety, or startup cost makes strict laziness inferior.

This is the governed bridge to Precomputation / Prefetching. The exception must name evidence, waste budget, freshness window, and rollback condition so the lazy parent does not silently become eager everywhere.

Common mechanisms

No mechanism is sufficient by itself. A thunk, proxy, generator, page-fault handler, or memoization library instantiates the archetype only when the surrounding demand, lifetime, failure, side-effect, concurrency, and measurement contracts are present.

Thunk or Lazy Promise

A software_or_tool mechanism. Package a computation and its captured environment as a value that can be forced later by demand.

It operationalizes deferred_work_unit, suspended_evaluation_state, input_lifetime_and_capture_rule. It is implementation machinery, not the parent archetype by itself.

Call-by-Need Evaluator

A method mechanism. Evaluate an argument only when first needed, then share the result across later references.

It operationalizes need_predicate, realization_path, result_sharing_policy, memoized_result_store. It is implementation machinery, not the parent archetype by itself.

Short-Circuit Evaluation

A method mechanism. Skip branches whose values cannot affect the requested result once an earlier condition determines the outcome.

It operationalizes need_predicate, deferred_dependency_map, realization_path. It is implementation machinery, not the parent archetype by itself.

Lazy Sequence Generator

A software_or_tool mechanism. Produce one sequence element or chunk at a time as the consumer advances rather than materializing the entire sequence.

It operationalizes deferred_work_unit, demand_boundary, realization_path, cycle_and_nontermination_guard. It is implementation machinery, not the parent archetype by itself.

Lazy-Initialization Proxy

A software_or_tool mechanism. Stand in for an expensive object or resource and initialize the real object on first qualifying access.

It operationalizes demand_boundary, activation_rule, suspended_evaluation_state, strictness_escape_hatch. It is implementation machinery, not the parent archetype by itself.

Late-Materialization Query Plan

A method mechanism. Delay fetching or constructing full records until filtering and projection establish which rows and fields are actually required.

It operationalizes deferred_dependency_map, need_predicate, latency_and_waste_budget. It is implementation machinery, not the parent archetype by itself.

Predicate Pushdown

A method mechanism. Move selection conditions closer to the data source so unnecessary rows or partitions are never realized upstream.

It operationalizes need_predicate, deferred_dependency_map, realization_path. It is implementation machinery, not the parent archetype by itself.

Demand-Driven Build Graph

A workflow mechanism. Traverse a declared dependency graph from the requested target and execute only stale prerequisites reachable from that target.

It operationalizes demand_signal, deferred_dependency_map, invalidation_rule, demand_and_realization_trace. It is implementation machinery, not the parent archetype by itself.

Demand Paging

A software_or_tool mechanism. Load a memory page or storage chunk only when an access fault demonstrates that the current working set needs it.

It operationalizes demand_boundary, activation_rule, latency_and_waste_budget, service_level_objective. It is implementation machinery, not the parent archetype by itself.

Copy-on-Write

A method mechanism. Share an existing representation until a write demand requires a private copy to be realized.

It operationalizes demand_boundary, need_predicate, result_sharing_policy. It is implementation machinery, not the parent archetype by itself.

Single-Flight Request Coalescing

A protocol mechanism. Make concurrent requests for the same absent result join one in-flight realization rather than trigger a thundering herd.

It operationalizes single_flight_and_duplicate_suppression_rule, result_sharing_policy, failure_and_exception_semantics. It is implementation machinery, not the parent archetype by itself.

Memoization

A software_or_tool mechanism. Store a realized function result under a stable input key so later demand can return it without repeating the computation.

It operationalizes memoized_result_store, result_sharing_policy, invalidation_rule. It is implementation machinery, not the parent archetype by itself.

Conditional Workflow Gate

A workflow mechanism. Release an expensive downstream task only when an earlier result or explicit request proves that the task is necessary.

It operationalizes need_predicate, activation_rule, cancellation_and_abandonment_rule. It is implementation machinery, not the parent archetype by itself.

On-Demand Report Generation

A workflow mechanism. Generate a costly report, drill-down, export, or simulation only when a user or downstream process requests that artifact.

It operationalizes demand_signal, realization_path, service_level_objective, demand_and_realization_trace. It is implementation machinery, not the parent archetype by itself.

Just-in-Time Compilation

A software_or_tool mechanism. Compile a code path when execution demand and runtime evidence justify paying the compilation cost.

It operationalizes demand_boundary, activation_rule, latency_and_waste_budget, prefetch_or_eager_exception_rule. It is implementation machinery, not the parent archetype by itself.

Deferred Database Query Object

A software_or_tool mechanism. Represent a query composition without executing it until iteration, materialization, or an explicit terminal operation demands results.

It operationalizes deferred_work_unit, demand_boundary, deferred_dependency_map, realization_path. It is implementation machinery, not the parent archetype by itself.

Parameter and tuning dimensions

A lazy design should make at least the following dimensions explicit:

  • Demand probability: the measured chance that a suspended unit is ever forced.
  • Demand granularity: whole object, field, row, page, element, chunk, branch, target, or workflow stage.
  • Realization cost: compute, I/O, bandwidth, energy, locks, remote calls, and scarce human work.
  • First-demand latency: median and tail delay experienced by the forcing caller.
  • Capture cost: memory and lifetime burden of retained inputs and closures.
  • Sharing identity: the exact key under which concurrent or later demand may reuse one result.
  • Freshness and invalidation: when a completed result stops matching current state.
  • Failure policy: retry, memoized failure, per-demand failure, fallback, or strict eager validation.
  • Cancellation policy: whether one waiter, all waiters, or the work owner can stop realization.
  • Side-effect class: pure, idempotent, compensatable, commit-gated, or forbidden.
  • Dependency closure: how accurately the system can prune unused branches.
  • Eager-exception threshold: when demand probability, deadline, or latency warrants prefetch or strict realization.

Invariants to preserve

  • A result is never presented as realized before its realization path completes and validation succeeds.
  • Only a legitimate demand or governed eager exception may activate a deferred unit.
  • The realized dependency closure is no broader than necessary for the requested result, except where a documented batching tradeoff applies.
  • Concurrent duplicate demand does not cause unbounded duplicate side effects or resource consumption.
  • Captured inputs, permissions, and versions are valid at realization or are explicitly reacquired and revalidated.
  • Result sharing never crosses scope, tenant, authorization, or version boundaries accidentally.
  • Deferred failure retains enough provenance to identify the suspended unit and original construction context.
  • Cancellation and invalidation release resources and do not leave unresolved shared state indefinitely.
  • Safety-critical, deadline-bound, and must-run work cannot disappear merely because no consumer requests a value.
  • The lazy path remains measurable against an eager or prefetched baseline.

Target outcomes

  • Lower compute, I/O, bandwidth, memory, energy, and initialization cost for unused work.
  • Faster startup and setup paths when optional features or branches are common.
  • Ability to represent large or potentially infinite sequences while consuming only finite demanded prefixes.
  • Smaller execution closures for target-specific builds, queries, workflows, and reports.
  • Fewer thundering-herd duplicates when concurrent demand is safely coalesced.
  • Clearer timing, failure, sharing, cancellation, and lifetime contracts than ad hoc lazy loading.
  • Better evidence for when to stay lazy, memoize, prefetch, batch, or force eagerly.
  • Reduced waste without silently transferring unacceptable delay or risk to first users.

Applicability

The pattern works best when unused work is common, demand is observable, and first-use cost is governable. It weakens when nearly everything is demanded, when failure must be discovered early, or when side effects cannot be separated from value production. A design should compare a lazy cohort with an eager or prefetched baseline rather than assuming that fewer early operations always mean lower total cost.

Cross-domain examples

Functional Programming

A function receives an expensive argument as a thunk and forces it only inside the branch that actually uses it.

Why it fits: The branch supplies a precise demand boundary, pure evaluation can be delayed, and call-by-need can share the result if referenced more than once.

Data Analytics

A query engine filters identifiers first and materializes large payload columns only for rows that survive the filter.

Why it fits: The projection and predicate define semantic need, so unused columns and rows never incur retrieval and decoding cost.

Software Builds

A build system starts from a requested target and executes only stale transitive prerequisites.

Why it fits: The target is the demand signal and the dependency graph identifies the minimum required closure.

User Interfaces

A complex editor module and its reference data load only when the user opens the editor.

Why it fits: Many sessions never use the feature, while first-use latency can be measured and selectively prefetched for high-probability users.

Storage And Memory

A virtual memory system loads a page only after an access fault proves the page belongs in the active working set.

Why it fits: Demand is concrete, resources are chunked, and locality makes avoided loading larger than fault and eviction overhead.

Decision Support

A dashboard computes a costly scenario drill-down only when the analyst expands that panel.

Why it fits: The report may never be viewed, but demand, provenance, cancellation, and latency can be explicit.

Workflow Automation

An expensive specialist review is created only when earlier evidence routes a case into the exceptional branch.

Why it fits: The need predicate prevents routine cases from consuming scarce review capacity while preserving an explicit safety and escalation boundary.

Neighbor distinctions

Precomputation / Prefetching

Precomputation / Prefetching spends resources before demand based on prediction to reduce response latency. This archetype withholds work until actual demand and accepts a controlled first-use cost. A governed design may combine them through a narrow eager exception, but the timing rule is opposite.

Strategic Caching

Strategic Caching governs where and how completed reusable results are stored, refreshed, invalidated, and evicted. This archetype governs whether work runs at all. Memoization is optional and introduces caching obligations only after first demand.

Dynamic Subproblem Reuse

Dynamic Subproblem Reuse identifies overlapping subproblems and reuses their solutions. Demand-triggered deferral can avoid untouched branches even when no subproblem repeats. The two combine when a demanded closure contains recurring subproblems.

Inversion of Control

Inversion of Control shifts initiative to a framework, recipient, or environment. It does not require a suspended result, need predicate, first-use semantics, or avoided work. A callback may trigger lazy realization but is only an initiation mechanism.

Option Preservation

Option Preservation delays irreversible commitment so more information can arrive. This archetype delays work until its result is needed; it can operate even when no strategic choice remains open.

Threshold-Based Activation

Threshold-Based Activation starts a response when a monitored condition crosses a cutoff. Here the default trigger is demand for a value or resource, not a state threshold, although demand may itself be filtered by a criterion.

Progressive Disclosure

Progressive Disclosure controls when information is revealed to a user. It may use lazy loading as a mechanism, but disclosure can stage already-prepared information and therefore does not own deferred computation semantics.

Minimum Sufficient Solution

Minimum Sufficient Solution permanently limits scope to what is necessary. Lazy evaluation may retain a larger possible scope but realizes only the portion demanded in a particular path.

Work-in-Progress Limiting

Work-in-Progress Limiting caps simultaneous active work after admission. This archetype controls whether a unit becomes active at all and may still need a WIP limit for many simultaneous demands.

Virtual Resource Abstraction

Virtual Resource Abstraction presents a logical resource independent of its physical backing. Demand paging is one lazy mechanism beneath that abstraction; the parent here generalizes demand-gated realization beyond virtualized resources.

Order-Independent Processing

Order-Independent Processing removes sensitivity to execution order. Laziness changes timing and may require order independence or side-effect isolation, but it does not guarantee commutativity.

Coupling Latency and Time-Delay Effects

Coupling Latency and Time-Delay Effects analyzes the consequences of delay in interactions. First-demand delay is one tradeoff here, while the parent intervention remains avoided realization until demand.

Recognized variants

Variants preserve recurring forms without multiplying duplicate parent archetypes.

Memoized Call-by-Need

Realize a deferred expression at most once per valid identity and share the memoized result across all later references.

Use when

  • The same deferred value may be demanded repeatedly.
  • The result is stable for the chosen identity or version.
  • Duplicate evaluation is costly or unsafe.

Distinctive feature. First demand changes the unit from suspended to a shared completed state rather than merely invoking the computation again.

Why it remains under the parent. The defining move remains demand-gated realization of work that otherwise may never execute.

Variant-specific failure modes

  • Stale memoized result
  • Unbounded retained result set
  • Failure is memoized longer than intended
  • Cross-tenant key collision

Repeat-on-Demand Call-by-Name

Reevaluate a deferred expression each time its value is demanded instead of sharing a prior realization.

Use when

  • The expression is cheap, state-sensitive, or intentionally reevaluated.
  • Retaining results would be more costly or misleading than recomputation.
  • The caller needs current state on every force.

Distinctive feature. Demand gates timing but does not create a persistent completed state.

Why it remains under the parent. Work remains suspended until demanded and may still be avoided entirely.

Variant-specific failure modes

  • Unexpected duplicate side effects
  • Repeated expensive work
  • Different values across references surprise callers

Lazy-Stream Incremental Realization

Realize only the next element or bounded chunk of a sequence as downstream consumption advances.

Use when

  • The full sequence is large, unbounded, or often only partially consumed.
  • Producer and consumer can coordinate through pull or bounded buffering.
  • Per-element cleanup and failure semantics are defined.

Distinctive feature. Demand is incremental and repeated, producing a finite prefix rather than one all-at-once value.

Why it remains under the parent. Each next element remains unrealized until demanded by the consumer.

Variant-specific failure modes

  • Resource remains open after partial consumption
  • Consumer stalls and retains upstream state
  • Unproductive infinite recursion

Deferred Initialization and Lazy Loading

Construct or load an expensive object, module, relationship, or resource only when a qualifying access first requires it.

Use when

  • Many created objects never use the expensive resource.
  • Initialization can be separated from object construction without violating invariants.
  • First-use delay and failure are acceptable or can be hidden safely.

Distinctive feature. The deferred unit is an object or resource lifecycle transition rather than a pure expression.

Why it remains under the parent. The resource remains unrealized until actual access crosses the demand boundary.

Variant-specific failure modes

  • First-access latency cliff
  • Initialization race
  • N+1 lazy-loading storm
  • Captured session is closed before access

Demand-Paged Resource Realization

Realize fixed-size pages or chunks only when access reaches them, while retaining a bounded working set and an eviction path.

Use when

  • The addressable resource is larger than active capacity.
  • Access locality makes a small realized working set effective.
  • Page-fault latency and eviction are governable.

Distinctive feature. Demand is expressed as access to an unrealized address range and realization is coupled to bounded working-set management.

Why it remains under the parent. Unneeded chunks remain unrealized and therefore consume no active loading or transformation work.

Variant-specific failure modes

  • Fault storm
  • Working-set thrashing
  • Eviction removes a still-needed chunk
  • Access pattern defeats locality

Dependency-Pruned Demand Execution

Start from a requested target and execute only the stale or missing dependency closure required to produce that target.

Use when

  • Work units form an explicit dependency graph.
  • Different targets require materially different subsets of the graph.
  • Staleness or validity can be determined per node.

Distinctive feature. The key optimization is graph reachability from the demanded target rather than a single suspended expression.

Why it remains under the parent. Nodes outside the demanded dependency closure remain unrealized.

Variant-specific failure modes

  • Missing dependency causes incorrect result
  • Cycle deadlock
  • Overbroad invalidation recomputes the whole graph
  • Nondeclarative side effects escape the graph

Copy-on-Write Realization

Share an existing state representation until a mutation demand forces a private copy or delta to be realized.

Use when

  • Read sharing is common and writes are comparatively rare.
  • Mutation isolation can be defined precisely.
  • Copy cost is high enough that avoiding unused copies matters.

Distinctive feature. The deferred work is state duplication and demand is a write rather than a read.

Why it remains under the parent. The expensive copy remains unrealized unless a write actually requires it.

Variant-specific failure modes

  • Unexpected copy storm
  • Aliasing leaks mutation
  • Copy occurs under lock and creates latency spike

Alias and collapse policy

lazy_evaluation and deferred_evaluation point to the parent. call_by_need points to the memoized subtype; lazy_loading points to deferred initialization. Memoization by itself remains a caching mechanism, a promise may be eager, and a callback may merely invert control. Deferred commitment belongs under Option Preservation, while forecast-triggered work belongs under Precomputation / Prefetching. This policy prevents implementation names from becoming duplicate archetypes.

Tradeoffs

  • Avoided unused work versus higher latency on first demand.
  • Lower startup cost versus deferred failure and validation timing.
  • Ability to represent large or infinite structures versus retained state and open-resource lifetime.
  • Result sharing versus storage, invalidation, authorization, and stale-result risk.
  • Concurrent request coalescing versus contention, shared failure fan-out, and head-of-line blocking.
  • Composability of deferred values versus harder reasoning about when code actually executes.
  • Reduced I/O and bandwidth versus N+1 request storms when demand granularity is too fine.
  • Minimal dependency closure versus overhead of maintaining accurate dependency and staleness metadata.
  • Cancellation savings versus complex cleanup and shared-demand semantics.
  • Late binding to current state versus reduced reproducibility when inputs are not versioned.
  • Memory saved by not materializing outputs versus memory retained by captured closures and dependency chains.
  • Energy and compute savings versus latency and burst load concentrated at user-visible moments.

Failure modes, causes, and mitigations

False demand or accidental forcing

Cause: Logging, serialization, debugging, equality checks, or interface inspection crosses an undefined demand boundary.

Mitigation: Specify forcing operations, provide nonforcing inspection, trace every force, and keep incidental tooling from materializing values silently.

Needed work never realizes

Cause: The demand signal or need predicate misses a legitimate consumption path.

Mitigation: Test target reachability, assert unresolved values at boundaries, add coverage traces, and fail visibly rather than returning placeholders as completed results.

Thundering-herd duplicate realization

Cause: Concurrent demanders observe the same suspended state and each starts the expensive work.

Mitigation: Use stable identity, atomic state transition, single-flight coalescing, bounded waiters, and explicit shared failure and cancellation semantics.

First-use latency cliff

Cause: A large dependency closure is deferred into a user-visible or deadline-critical interaction.

Mitigation: Measure tail latency, split work into chunks, prefetch high-probability units under a budget, expose progress, or force selected work during a safer phase.

Space leak from retained captures

Cause: Suspended units retain large object graphs, buffers, sessions, or references long after their likely demand window.

Mitigation: Capture minimally, use weak or versioned references where appropriate, set expiry, release after completion or cancellation, and monitor retained bytes per unresolved unit.

Use-after-close or expired context

Cause: A deferred unit depends on a transaction, file, credential, request scope, or snapshot that ends before first use.

Mitigation: Reacquire resources at realization, capture immutable data rather than handles, bind version tokens, and validate lifetime explicitly.

Deferred side-effect surprise

Cause: Evaluation performs externally visible effects whose timing or multiplicity callers assumed occurred earlier or only once.

Mitigation: Separate pure value production from commit, make effects idempotent, declare execution timing, and reject call-by-name for nonrepeatable effects.

Failure appears far from cause

Cause: Construction succeeds but invalid inputs, missing dependencies, or permissions fail only when the value is forced later.

Mitigation: Preserve construction provenance, validate cheap structural preconditions early, attach causal traces, and provide an eager validation mode for critical paths.

Stale or wrongly shared memoized result

Cause: The sharing key omits relevant input, version, tenant, role, locale, or policy state.

Mitigation: Define result identity explicitly, include version and authorization scope, test key completeness, and invalidate on every relevant dependency change.

Lazy-loading N+1 storm

Cause: Fine-grained per-item demand triggers many remote loads after iteration begins.

Mitigation: Trace request multiplicity, batch or prefetch the proven working set, expose collection-level demand, and place budgets on remote realization counts.

Recursive demand cycle or black hole

Cause: A deferred unit directly or indirectly demands its own unresolved result without productive progress.

Mitigation: Track in-flight dependency stacks, detect cycles, distinguish productive recursive streams, enforce step or time bounds, and provide explicit fixed-point handling where appropriate.

Cancellation leaks resources or corrupts shared state

Cause: The original demander disappears while work is in flight, but cleanup and shared-waiter ownership are undefined.

Mitigation: Separate requester cancellation from shared-work cancellation, make cleanup idempotent, release leases in finally paths, and record partial side effects for compensation.

Laziness masks must-run obligations

Cause: Maintenance, safety, compliance, backup, or aging work is deferred indefinitely because no consumer explicitly requests its output.

Mitigation: Classify deadline-bound work as scheduled or event-driven obligations, not lazy values, and audit unresolved units for age and must-run status.

Observability forces or distorts evaluation

Cause: Instrumentation either materializes values to inspect them or omits the hidden demand-to-realization path.

Mitigation: Use nonforcing metadata, state-transition events, sampled payload inspection, and separate demand, start, completion, failure, reuse, cancellation, and invalidation metrics.

Eager fallback spreads without evidence

Cause: Teams force everything to avoid isolated latency surprises, erasing the original waste reduction.

Mitigation: Scope the strictness escape hatch, require measured justification, compare eager and lazy cohorts, and revisit after dependency or usage changes.

Extended example

A fraud-operations platform displays a case summary immediately but offers an expensive network-analysis drill-down. The team first measures that only 8 percent of cases open the drill-down, while eager graph assembly accounts for 35 percent of case-load time. They represent graph assembly as a deferred work unit keyed by case version and analyst permission scope. Opening the panel is the demand boundary. The need predicate verifies that the case still exists, the user may view linked entities, and no valid result is already present. A dependency map selects only the transaction, identity, and device edges required by the chosen time window. The first valid demand atomically moves the unit from suspended to running; concurrent requests join one single-flight realization. The graph builder has no external side effects, publishes a versioned result, and stores it for a short reuse window. Cancellation removes the analyst as a waiter but stops the shared job only when no waiters remain. Failures preserve the original case and query provenance, and an eager validation mode runs on a sample of cases to detect dependency drift. Metrics compare avoided graph builds, first-panel latency, duplicate suppression, retained memory, cancellation waste, stale-result rate, and user distribution by network speed. When the panel becomes common in one workflow, a governed prefetch exception warms that cohort after case selection while the default remains demand-triggered.

Non-examples

  • Running a forecasted report overnight before anyone requests it.
  • Keeping a completed response in a cache near users.
  • Waiting for CPU utilization to cross 80 percent before adding workers.
  • Delaying a procurement decision until market uncertainty resolves.
  • Putting required maintenance in a backlog and calling it lazy because no failure has occurred yet.
  • Registering a callback when the callback always performs eager work regardless of whether its result is consumed.
  • Initializing every plugin at startup and merely hiding its interface until opened.
  • Using a promise whose producer starts immediately; the promise may be asynchronous but is not lazy.

Adoption checklist

Before adopting the pattern, answer these questions:

  1. What exact event proves the result is needed?
  2. What work and dependencies remain suspended before that event?
  3. What percentage of units are never demanded, and what cost is actually avoided?
  4. What first-use latency and deferred-failure behavior will callers observe?
  5. Can concurrent equivalent demand share one realization safely?
  6. Which inputs, permissions, sessions, and versions must survive until first use?
  7. Are side effects isolated, idempotent, compensatable, or explicitly committed?
  8. How are cancellation, invalidation, and cleanup handled?
  9. How will traces reveal demand, start, completion, reuse, failure, and abandonment?
  10. What measured condition justifies forcing or prefetching the work eagerly?

Common Mechanisms

  • Call-by-Need Evaluator — Evaluates an expression only when its value is demanded, propagates that demand through everything the value depends on, and evaluates each suspended piece at most once.
  • Conditional Workflow Gate — Guards an expensive stage of a workflow behind a cheap predicate, so the stage runs only when its output will actually be used.
  • Copy-on-Write — Lets many holders share one physical copy of some data and defers the actual copy until a holder first writes, so unmodified sharing costs nothing.
  • Deferred Database Query Object — Represents a database query as a composable object that builds up lazily and only touches the database when its results are actually iterated.
  • Demand Paging — Loads a page of memory from backing store only when a program actually touches it, turning the page fault into the signal that the data is finally needed.
  • Demand-Driven Build Graph — Models work as a dependency graph and, given a requested output, realizes only the subgraph that output depends on and whose inputs have changed.
  • Just-in-Time Compilation — Defers translating code into fast native form until running demand — and repeated use — proves a path hot enough to repay the compilation.
  • Late-Materialization Query Plan — Carries lightweight column positions through a query and reconstructs full rows only at the end, for only the rows and columns that survive.
  • Lazy Sequence Generator — Produces a sequence one element at a time, computing each only when the consumer pulls for it — and never computing elements no one asks for.
  • Lazy-Initialization Proxy — A transparent stand-in that looks like the real object but constructs it only on first genuine use, then forwards every call to the one real instance.
  • Memoization — Stores the result of a computation keyed by its inputs, so a repeat call with the same inputs returns the saved value instead of recomputing it.
  • On-Demand Report Generation — Builds a report only when a user actually requests it, and re-checks — at generation time — who is asking and whether they still want to wait.
  • Predicate Pushdown — Moves a query's filters down to the data source so rows that cannot match are never read, decoded, or transmitted in the first place.
  • Short-Circuit Evaluation — Evaluates a boolean expression left to right and stops the instant the result is settled, so later operands — and their side effects — never run.
  • Single-Flight Request Coalescing — When several callers demand the same not-yet-ready value at once, runs the computation a single time and hands that one result to every waiter.
  • Thunk or Lazy Promise — Packages an unevaluated computation as a first-class value that runs at most once when forced — relocating its side effects and failures to force-time.

Compression statement

Identify work whose result may never be consumed; specify a demand boundary and need predicate; capture only valid inputs and dependencies; keep the work suspended; on valid demand, coordinate one bounded realization of the minimum required closure; publish, share, memoize, or discard the result according to policy; isolate side effects; expose deferred failures; support cancellation and invalidation; measure avoided work against first-use latency, memory retention, coordination cost, and observability loss; and force selected work eagerly when safety, deadlines, deterministic failure timing, or resource release requires it.

Canonical formula: Realize W only if Need(W, demand, state)=true; execute Closure(W) once per sharing identity when permitted; prefer laziness when P(not demanded)·Cost(W) > AddedLatency(W) + RetentionCost(W) + CoordinationCost(W) + DeferredFailureRisk(W), subject to side-effect, authorization, validity, and service-level invariants.

Abstractions this archetype builds on — directly (a source ingredient) or as a related pattern. Links follow the typed catalog namespace.

Built directly on (4)

  • Cost–Benefit Analysis: Evaluate decisions.
  • Dependency: Directed relation in which one element relies on another being present, prior, compatible, or supplied, with a specifiable failure mode if the condition is unmet.
  • Lazy Evaluation: Defer work until its result is actually demanded.
  • Postponement: Delay the point at which a system commits to a final configuration until more information about which configuration is wanted arrives, trading earliness for accuracy.

Also references 18 related abstractions

  • Algorithm: Step-by-step problem-solving procedure.
  • Caching: Store for faster retrieval.
  • Callback: A named action handed off in advance, to be invoked later by someone else when a specified condition arises, releasing the registrant from synchronous waiting.
  • Concurrency: Manage simultaneous processes.
  • Data Integrity: Accuracy and consistency preserved.
  • Future Or Promise: A first-class placeholder for a value committed to be supplied later.
  • Idempotence: Repetition yields same result.
  • Latency: The irreducible delay between an input and the system's response.
  • Locality Of Reference: Accesses cluster in time and space, making prediction and caching effective.
  • Observability: Infer internal state externally.

Variants

Narrower or domain-specific specializations that share this archetype's core structure. Recognized variants are established; candidate variants are provisional.

Memoized Call-by-Need · subtype · recognized

Realize a deferred expression at most once per valid identity and share the memoized result across all later references.

  • Distinct from parent: The parent permits recomputation or one-shot results; this subtype requires result sharing and therefore imports storage, identity, freshness, and invalidation obligations.
  • Use when: The same deferred value may be demanded repeatedly; The result is stable for the chosen identity or version; Duplicate evaluation is costly or unsafe.
  • Typical domains: functional programming, dependency injection, expensive configuration, remote data access
  • Common mechanisms: call by need evaluator, memoization, single flight request coalescing

Repeat-on-Demand Call-by-Name · subtype · recognized

Reevaluate a deferred expression each time its value is demanded instead of sharing a prior realization.

  • Distinct from parent: The parent leaves sharing open; this subtype explicitly chooses repeat evaluation and therefore requires strong side-effect and cost controls.
  • Use when: The expression is cheap, state-sensitive, or intentionally reevaluated; Retaining results would be more costly or misleading than recomputation; The caller needs current state on every force.
  • Typical domains: language evaluation, dynamic configuration, reactive views
  • Common mechanisms: thunk or lazy promise, short circuit evaluation

Lazy-Stream Incremental Realization · subtype · recognized

Realize only the next element or bounded chunk of a sequence as downstream consumption advances.

  • Distinct from parent: The parent also covers one-shot deferred units; this subtype centers productive prefixes, backpressure, and resource lifetime across an open sequence.
  • Use when: The full sequence is large, unbounded, or often only partially consumed; Producer and consumer can coordinate through pull or bounded buffering; Per-element cleanup and failure semantics are defined.
  • Typical domains: data processing, network streams, search results, event logs
  • Common mechanisms: lazy sequence generator, predicate pushdown

Deferred Initialization and Lazy Loading · subtype · recognized

Construct or load an expensive object, module, relationship, or resource only when a qualifying access first requires it.

  • Distinct from parent: This subtype emphasizes initialization state, resource ownership, reentrancy, and use-after-close hazards.
  • Use when: Many created objects never use the expensive resource; Initialization can be separated from object construction without violating invariants; First-use delay and failure are acceptable or can be hidden safely.
  • Typical domains: application startup, object relational mapping, plugin systems, user interfaces
  • Common mechanisms: lazy initialization proxy, deferred database query object

Demand-Paged Resource Realization · subtype · recognized

Realize fixed-size pages or chunks only when access reaches them, while retaining a bounded working set and an eviction path.

  • Distinct from parent: The parent does not require fixed-size pages, eviction, or locality; this subtype does.
  • Use when: The addressable resource is larger than active capacity; Access locality makes a small realized working set effective; Page-fault latency and eviction are governable.
  • Typical domains: virtual memory, columnar storage, remote object stores, geospatial tiles
  • Common mechanisms: demand paging, late materialization query plan

Dependency-Pruned Demand Execution · subtype · recognized

Start from a requested target and execute only the stale or missing dependency closure required to produce that target.

  • Distinct from parent: The parent covers any demand-gated work; this subtype requires explicit dependency traversal, staleness checks, and target-oriented scheduling.
  • Use when: Work units form an explicit dependency graph; Different targets require materially different subsets of the graph; Staleness or validity can be determined per node.
  • Typical domains: build systems, data pipelines, workflow orchestration, spreadsheet recalculation
  • Common mechanisms: demand driven build graph, conditional workflow gate

Copy-on-Write Realization · subtype · recognized

Share an existing state representation until a mutation demand forces a private copy or delta to be realized.

  • Distinct from parent: The parent mostly describes value demand; this subtype applies the same timing logic to mutation-triggered state separation.
  • Use when: Read sharing is common and writes are comparatively rare; Mutation isolation can be defined precisely; Copy cost is high enough that avoiding unused copies matters.
  • Typical domains: operating systems, persistent data structures, snapshotting, document editing
  • Common mechanisms: copy on write

Near names: Lazy Evaluation, Call-by-Need, Deferred Evaluation, Demand-Driven Evaluation, Need-Driven Computation, On-Demand Evaluation, Lazy Loading, Deferred Computation.