Call by Value vs Call by Name

For a parameter listed in the value part, the actual parameter is evaluated once at call time and the formal behaves like a local variable initialized with that value.

15.1 Call by value

For a parameter listed in the value part, the actual parameter is evaluated once at call time and the formal behaves like a local variable initialized with that value. Assignments to it do not affect the caller.

15.2 Call by name: the copy rule

For every other parameter, the Report defines the semantics by the copy rule: the call behaves as if the procedure body were copied into the call site with every occurrence of the formal parameter textually replaced by the actual parameter (enclosed in parentheses, with identifiers renamed to avoid clashes). So the actual parameter expression is re-evaluated every time the formal is used, in the caller's environment.

'begin'
    'integer' i;
    'integer' 'array' a[1:3];

    'procedure' show twice(x); 'integer' x;
    'begin'
        outinteger(1, x);
        i := i + 1;
        outinteger(1, x)          'comment' x re-evaluated: now a[i] with the new i;
    'end';

    a[1] := 10; a[2] := 20; a[3] := 30;
    i := 1;
    show twice(a[i]);             'comment' prints 10 then 20;
    outstring(1, "\n")
'end'

15.3 Assigning to a by-name parameter

If the actual parameter is a variable (or subscripted variable), assigning to the formal assigns to that variable in the caller — giving the effect of call by reference, but with the address recomputed at each use:

If the actual is an expression like n + 1, assigning to the formal is an error (undefined behavior in ALGOL 60; MARST reports a run-time error).

'procedure' increment(x); 'integer' x; x := x + 1;
...
increment(count);        'comment' count := count + 1;
increment(a[k]);         'comment' a[k] := a[k] + 1 (k evaluated twice);

15.4 The famous swap problem

With call by name, it is impossible to write a general swap procedure in ALGOL 60 — a classic result. Swapping swap(x[i], i) happens to work, but swap(i, x[i]) fails. (This program deliberately fails with a subscript error.)

'begin'
    'integer' i;
    'integer' 'array' x[1:5];
    'procedure' swap(a, b); 'integer' a, b;
    'begin' 'integer' t; t := a; a := b; b := t 'end';

    'for' i := 1 'step' 1 'until' 5 'do' x[i] := 10 * i;
    i := 1;
    swap(i, x[i]);
    'comment' expected: i = 10, x[1] = 1;
    'comment' actual:   t := i (1); i := x[i] (x[1] = 10); x[i] := t means x[10] := 1 (out of bounds);
'end'

15.5 When to use value

Input-only scalar (n, tolerance) value — faster and safer Output or in-out variable name (the only way to return results through parameters) Large array, read-only name (avoids copying)

Expression to be re-evaluated (Jensen's device) name — intentionally Procedure, label, switch, string name (value is not meaningful for these)

Rule of thumb: put every scalar input parameter in the value list unless you intend name semantics.

15.6 Cost of call by name

Each use of a by-name formal requires calling a small hidden routine (a thunk, Chapter 16), which made ALGOL 60 programs slower than FORTRAN when programmers forgot value. This cost was one reason ALGOL W introduced result / value result parameters, Pascal adopted var (by reference) and value parameters, and ALGOL 68 dropped call by name entirely (replacing it with explicit procedure parameters).