[1] The term is often used to refer to the more specific notion of a parameter-passing strategy[2] that defines the kind of value that is passed to the function for each parameter (the binding strategy)[3] and whether to evaluate the parameters of a function call, and if so in what order (the evaluation order).
[clarification needed] This is a table of evaluation strategies and representative languages by year introduced.
For example, the Python program outputs 123 due to Python's left-to-right evaluation order, but a similar program in OCaml: outputs 213 due to OCaml's right-to-left evaluation order.
[26] OCaml similarly leaves the order unspecified, but in practice evaluates arguments right-to-left due to the design of its abstract machine.
[28] With normal order evaluation, expressions containing an expensive computation, an error, or an infinite loop will be ignored if not needed,[4] allowing the specification of user-defined control flow constructs, a facility not available with applicative order evaluation.
[33] Normal order evaluation has historically had a lack of usable debugging tools due to its complexity.
However, a call-by-reference language makes it more difficult for a programmer to track the effects of a function call, and may introduce subtle bugs.
A simple litmus test is if it's possible to write a traditional swap(a, b) function in the language.
When the function call returns, the updated contents of this variable are copied back to overwrite the original argument ("restored").
[38] For example, Ada specifies that the copy-out assignment for each in out or out parameter occurs in an arbitrary order.
This strategy has gained attention in multiprocessing and remote procedure calls,[41] as unlike call-by-reference it does not require frequent communication between threads of execution for variable access.
[44] The term "call by sharing" as used in this article is not in common use; the terminology is inconsistent across different sources.
For example, this code binds the formal argument to a new object, but it is not visible to the caller because it does not mutate a_list:
[47] Other authors take a differing view that the presented implementation of swap in C is only a simulation of call-by-reference using pointers.
[48] Under this "simulation" view, mutable variables in C are not first-class (that is, l-values are not expressions), rather pointer types are.
C++ confuses the issue further by allowing swap to be declared and used with a very lightweight "reference" syntax:[50] Semantically, this is equivalent to the C examples.
As such, many authors consider call-by-address to be a unique parameter passing strategy distinct from call-by-value, call-by-reference, and call-by-sharing.
In logic programming, the evaluation of an expression may simply correspond to the unification of the terms involved combined with the application of some form of resolution.
Java programs can accomplish similar lazy evaluation using lambda expressions and the java.util.function.Supplier
Because evaluation of expressions may happen arbitrarily far into a computation, Haskell supports only side effects (such as mutation) via the use of monads.
This eliminates any unexpected behavior from variables whose values change prior to their delayed evaluation.
In R's implementation of call by need, all arguments are passed, meaning that R allows arbitrary side effects.
Macro substitution may therefore result in variable capture, leading to mistakes and undesired behavior.
Hygienic macros avoid this problem by checking for and replacing shadowed variables that are not parameters.
The method requires fine-grained dynamic scheduling and synchronization but is suitable for massively parallel machines.
[52] However, call-by-future may perform unnecessary speculative work compared to call-by-need, such as deeply evaluating a lazy data structure.
[53] This approach avoids some of call-by-need's runtime expenses while retaining desired termination characteristics.