In most languages alpha-conversion is a valid rule for formal parameters. This implies that the details which are hidden from the user of a function or procedure include the names of formal parameters.
So which actual arguments match which formals should not be specified by name. It is usually specified by position: the parameter type of a function is a tuple type.
In Ada arguments can be specified by name using the same notation as for record aggregates. For example a function call might be:
This allows actual arguments to be given out of order, and default values can be used for unspecified arguments: e.g. epsilon above could have been left out if the default value was satisfactory. Common Lisp also has named parameters.integrate(epsilon => 0.001, f => sine, a => 0.0, b => pi);
The point to notice here is that expressions are never passed as arguments in mainstream languages. They are always evaluated first, and the result values are passed.
Remember the discussion of evaluation order for expressions. An operation like + applied to two arguments, e.g. 2*x + 3*y is really a function-call plus(times(2,x),times(3,y)).
The most important rule of expression evaluation is that arguments are
evaluated before the function applied to them is called, but if-then-else
is
special. Languages differ in whether or not it is specified in what
order multiple arguments are evaluated.
Given the call "p(e1,e2)" where e1 evaluates to the value a1 and e2 evaluates to the value a2, the simplest semantics of parameter-passing says that the call is equivalent to executing the blockprocedure p(f1,f2:t);
var x: t;
begin
...
end;
This method of parameter-passing is called call-by-value. A variant allows f1 and f2 to be local variables as opposed to local constants.begin
const f1 := a1;
const f2 := a2;
var x: t;
...
end;
the call "p(x)" where x is the name of a variable is equivalent toprocedure p(inout f:t);
begin
...
end;
Call by value-result is used in Ada.begin
var f:t := a; // "a" denotes the current value of x
...
x := f;
end;
This is the semantics of Pascal "var" parameter-passing. We can explain it more formally as follows. Given
the call "p(x)" where x is the name of a variable is equivalent toprocedure p(var f:t);
begin
...
end;
In some languages, for example C, call-by-reference is not available but in can be achieved by using call-by-value and passing the location of a variable instead of its value.begin
const f: pointer to t := location(x);
...
end;
Consider the pseudo-Pascal summation function
With call-by-macro the actual argument expressions for k and f will be evaluated again each time the formal parameter is used, so we can write for example sum(1,n,j,a[j]*b[j]) to compute the dot-product of two vectors a and b of length n.function sum (lo,hi:int; macro k:int; macro f:real): real;
var s: real := 0;
begin
for k := lo to hi do s := s + f;
return s;
end;
Consider the pseudo-Pascal summation function using call-by-macro from above. This can be implemented using call-by-value with function arguments:
The lesson to learn here is that higher-order functions give the functionality of call-by-macro.function sum (lo,hi:int; ref k:int; f:void->real);
var s: real := 0;
begin
for k := lo to hi do s := s + f();
return s
end;function f(): real;
begin
return a[j]*b[j];
end;
Copyright (c) 2002 by Charles Elkan.