What is "pass-by-name" and how does it work exactly?
I'm assuming you mean call-by-name in ALGOL 60.
Call-by-name is similar to call-by-reference in that you can change the value of the passed in parameter. It differs from call-by-reference in that the parameter is not evaluated before the procedure is called but is instead evaluated lazily. That is, it is evaluated when and only when the parameter is actually used.
For example, suppose we have a procedure f(x, y)
and we pass it i
and i/2
where i
is initially equal to 10
. If f
sets x
to 42
and then evaluates y
it will see the value 21
(whereas with call by reference or call by value it would still see 5
). This is because the expression i/2
isn't evaluated until y
is evaluated.
In many ways this appears to behave like a literal text-substitution of the parameters (with renaming to avoid name conflicts). In practice, however, this is implemented using "thunks" (basically closures) for the passed in expressions.
The Wikipedia article on Jensen's Device shows some interesting examples of using call by name. Here is one of them:
real procedure Sum(k, l, u, ak) value l, u; integer k, l, u; real ak; comment k and ak are passed by name; begin real s; s := 0; for k := l step 1 until u do s := s + ak; Sum := s end;
In the procedure, the index variable
k
and summation termak
are passed by name. Call by name enables the procedure to change the value of the index variable during execution of the for loop. Call by name also causes theak
argument to be reevaluated during each iteration of the loop. Typically,ak
will depend upon the changing (side-effected)k
.For example, code to compute the sum of the first 100 terms of a real array
V[]
would be:Sum(i, 1, 100, V[i]).
Actually, call-by-name, is not just a historical curiosity. You can do call-by-name in Windows batch files (and myriad of other scripting languages). Knowing how it works, and how to use it effectively in programming can open up neat solutions to problems. I know it is only passing strings through for later expansion, but it can be manipulated to have similar effects as call-by-name.
call :assign x 1
exit /b
:assign
setlocal enabledelayedexpansion
(endlocal
:: Argument 1 is the name of the variable
set %1=%2
)
exit /b
For those in the future:
Concepts in Programming Languages by John C. Mitchell was also helpful.
Pass-by-Name. Perhaps the strangest feature of Algol 60, in retrospect, is the use of pass-by-name. In pass-by-name, the result of a procedure call is the same as if the formal parameter were substituted into the body of the procedure. This rule for defining the result of a procedure call by copying the procedure and substituting for the formal parameters is called the Algol 60 copy rule. Although the copy rule works well for pure functional programs, as illustrated by β reduction in lambda calculus, the interaction with side effects to the formal parameter are a bit strange. Here is an example program showing a technique referred to as Jensen's device: passing an expression and a variable it contains to a procedure so that the procedure can use one parameter to change the location referred to by the other:
begin integer i; integer procedure sum(i, j); integer i, j; comment parameters passed by name; begin integer sm; sm := 0; for i := 1 step 1 until 100 do sm := sm + j; sum := sm end; print(sum(i, i*10 )) end
In this program, the procedure sum(i,j) adds up the values of j as i goes from 1 to 100. If you look at the code, you will realize that the procedure makes no sense unless changes to i cause some change in the value of j; otherwise, the procedure just computes 100*j. In the call sum(i, i*10) shown here, the for loop in the body of procedure sum adds up the value of i*10 as i goes from 1 to 100.
I found a good explanation at Pass-By-Name Parameter Passing. Essentially, the body of a function is interpreted at call time after textually substituting the actual parameters into the function body. In this sense the evaluation method is similar to that of C preprocessor macros.
By substituting the actual parameters into the function body, the function body can both read and write the given parameters. In this sense the evaluation method is similar to pass-by-reference. The difference is that since with pass-by-name the parameter is evaluated inside the function, a parameter such as a[i]
depends on the current value of i
inside the function, rather than referring to the value at a[i]
before the function was called.
The page I linked above has some more examples of where pass-by-name is both useful, and dangerous. The techniques made possible by the pass-by-name are largely superseded today by other, safer techniques such as pass-by-reference and lambda functions.