Call By NameEdit
Call by name is a parameter passing strategy used in some programming languages and in language semantics to determine when and how the actual arguments to functions are evaluated. In this approach, the argument expression is not directly passed as a value or a precomputed result. Instead, the callee sees a substitute for the expression that is evaluated each time the parameter is used, often by replacing occurrences of the parameter with the original argument expression. The result is a flexible, if sometimes fragile, way to control evaluation order and side effects. This notion is closely tied to historical ideas about how to model computation, and it has influenced subsequent concepts such as laziness and thunk-based implementation. Algol 60 and lambda calculus discussions of evaluation order helped crystallize the idea, and the strategy remains a touchstone in discussions of language semantics.
Call by name is often contrasted with call by value, in which the argument is evaluated before entering the callee, and with call by need (lazy evaluation with sharing), in which the argument is evaluated at most once and the result is reused. In call by name, evaluation can occur multiple times if the parameter is used more than once, and it can be avoided entirely if the parameter is not used. This makes the mechanism powerful in theory but potentially expensive in practice, depending on how the callee uses the parameter and whether the argument expression has side effects. The concept is frequently explained with the idea of a thunk, a delayed computation that captures the argument expression and its environment and that is forced (evaluated) when the parameter is accessed. Compare this with a direct thunk or with lazy evaluation where sharing is used to avoid repeated work.
Historically, call by name played a central role in early language design. In particular, Algol 60 used a pass-by-name mechanism for parameters, which allowed a form of macro-like substitution with delayed evaluation and introduced important considerations about variable binding and scope. The formalization and critique of by-name semantics were advanced by researchers such as Peter Landin and others who studied how Algol-like languages relate to the theory of computation, including lambda calculus representations of programs. The by-name approach helped illuminate the distinction between preparing an argument for use and merely computing a value in advance, a distinction that continues to inform how we reason about language features today. See also discussions of call by value and call by need in the evolution of language design.
Semantics
How it works: In a by-name call, the function body contains references to the parameter that are replaced by the actual argument expression in a way that is evaluated only as needed. The evaluation of the argument is therefore deferred until its value is actually required during the function’s execution. This is frequently implemented via a thunk that captures the environment and postpones evaluation until forced. The thunk may be forced multiple times if the parameter is used multiple times.
Notes on binding and scope: Because the argument expression is substituted for the parameter, one must be careful about variable capture and renaming. Renaming (alpha-conversion) is often used conceptually to avoid accidentally binding free variables in the argument to the callee’s variables. The result can be subtle when side effects are involved.
Implications for side effects and referential transparency: If the argument expression includes side effects (for example, performing I/O or mutating state), call by name makes those effects occur each time the parameter is used, which can lead to surprising or undesirable behavior. In purely functional settings where side effects are absent, many of these concerns do not arise, but the practicality of call-by-name semantics remains dependent on how the language handles effects and state. See also side effects and referential transparency.
Examples and intuition: If a function f(a) uses a only once, call by name behaves similarly to call by value for that particular call. If a is used twice, the argument’s expression could be evaluated twice under by-name semantics, whereas it would be evaluated once under by-value semantics or shared once under call by need. This difference is at the heart of the efficiency and predictability trade-offs associated with by-name evaluation.
History and landscape
Origins and influence: Call by name emerged from early discussions of how to model parameter passing in Algol-like languages and to connect language semantics with theories of computation. It provided a framework in which the evaluation order of arguments could be explored as a parameter-passing discipline rather than as a fixed pre-evaluation step. See Algol 60 for concrete language design choices that illustrated these ideas.
Relationship to other strategies: The by-name approach is one point on a spectrum that includes call by value (eager evaluation) and call by need (lazy evaluation with sharing). Each position has a different set of trade-offs in terms of performance, predictability, and ease of reasoning about code. See call by value and lazy evaluation for related discussions.
Modern relevance: In contemporary languages, by-name semantics are less common as a primary evaluation strategy, but the concepts survive in the study of language design, macro systems, and non-strict evaluation. The practical concern is often how to manage overhead, maintainability, and the risk of unintended effects when arguments can be evaluated multiple times. The idea of delaying computation (thunks) remains a foundational tool in implementing lazy or non-strict features in many systems. See thunk and lambda calculus discussions of evaluation order.
Controversies and debates
When to use by-name semantics: Advocates emphasize its theoretical elegance and the flexibility it provides for expressions that may not always be needed or that benefit from postponing work until it is certain to be necessary. Critics point to the potential for hidden costs, non-deterministic behavior with side effects, and the difficulty of reasoning about performance when argument evaluation can vary by use.
Predictability vs. laziness: By-name evaluation offers a form of non-strictness, but without the sharing precautions of call by need, it can lead to repeated work. This makes performance harder to predict and can create maintenance challenges in large codebases where side effects are present. The mainstream shift in many language communities has been toward evaluation strategies that balance laziness with sharing (call by need) or toward strictness (call by value) with careful design to control when evaluation happens.
Reference vs. substitution semantics: By-name semantics can be seen as a model of textual substitution at the level of parameter binding, which raises questions about efficiency and implementation complexity compared to value-based approaches. The debate often centers on the extent to which an implementation should rely on optimizing substitution, capturing environments, and sharing results, or instead rely on clearer, more predictable evaluation rules.
Practical stance from a performance and reliability viewpoint: In environments where resource usage, latency, and maintainability are prioritized—whether in systems programming, real-time contexts, or large-scale software engineering—the by-name approach is usually weighed against the more predictable and optimizable alternatives. Languages and platforms favor strategies that minimize surprises for developers while delivering acceptable performance, often leading to a preference for by-value or by-need in practice. See also referential transparency and side effects for the broader implications on correctness and reasoning.