There are six major mechanisms for passing data to and from a procedure, they are
You also have to worry about where you can pass parameters. Common places are
Finally, the amount of data has a direct bearing on where and how to pass it. The following sections take up these issues.
CallProc(I);
If you pass I
by value, the CallProc
does not change the value of I
, regardless of what happens to the parameter inside CallProc
.
Since you must pass a copy of the data to the procedure, you should only use this method for passing small objects like bytes, words, and double words. Passing arrays and strings by value is very inefficient (since you must create and pass a copy of the structure to the procedure).
program main(input,output); var m:integer; procedure bletch(var i,j:integer); begin i := i+2; j := j-i; writeln(i,' ',j); end; . . . begin {main} m := 5; bletch(m,m); end.
This particular code sequence will print "00" regardless of m
's value. This is because the parameters i
and j
are pointers to the actual data and they both point at the same object. Therefore, the statement j:=j-i;
always produces zero since i
and j
refer to the same variable.
Pass by reference is usually less efficient than pass by value. You must dereference all pass by reference parameters on each access; this is slower than simply using a value. However, when passing a large data structure, pass by reference is faster because you do not have to copy a large data structure before calling the procedure.
Bletch
returns to the calling code, m
could only contain one of the two values, but while Bletch
is executing, i
and j
would contain distinct values.
#define
macro facility in the C programming language. This parameter passing mechanism uses textual substitution on the parameters. Consider the following MASM macro:PassByName macro Parameter1, Parameter2 mov ax, Parameter1 add ax, Parameter2 endm
If you have a macro invocation of the form:
PassByName bx, I
MASM emits the following code, substituting bx for Parameter1 and I for Parameter2:
mov ax, bx add ax, I
Some high level languages, such as ALGOL-68 and Panacea, support pass by name parameters. However, implementing pass by name using textual substitution in a compiled language (like ALGOL-68) is very difficult and inefficient. Basically, you would have to recompile a function everytime you call it. So compiled languages that support pass by name parameters generally use a different technique to pass those parameters. Consider the following Panacea procedure:
PassByName: procedure(name item:integer; var index:integer); begin PassByName; foreach index in 0..10 do item := 0; endfor; end PassByName;
Assume you call this routine with the statement PassByName(A[i], i);
where A
is an array of integers having (at least) the elements A[0]..A[10]. Were you to substitute the pass by name parameter item you would obtain the following code:
begin PassByName; foreach index in 0..10 do A[I] := 0; (* Note that index and I are aliases *) endfor; end PassByName;
This code zeros out elements 0..10 of array A
.
High level languages like ALGOL-68 and Panacea compile pass by name parameters into functions that return the address of a given parameter. So in one respect, pass by name parameters are similar to pass by reference parameters insofar as you pass the address of an object. The major difference is that with pass by reference you compute the address of an object before calling a subroutine; with pass by name the subroutine itself calls some function to compute the address of the parameter.
So what difference does this make? Well, reconsider the code above. Had you passed A[I]
by reference rather than by name, the calling code would compute the address of A[I]
just before the call and passed in this address. Inside the PassByName
procedure the variable item
would have always referred to a single address, not an address that changes along with I
. With pass by name parameters, item
is really a function that computes the address of the parameter into which the procedure stores the value zero. Such a function might look like the following:
ItemThunk proc near mov bx, I shl bx, 1 lea bx, A[bx] ret ItemThunk endp
The compiled code inside the PassByName procedure might look something like the following:
; item := 0; call ItemThunk mov word ptr [bx], 0
Thunk is the historical term for these functions that compute the address of a pass by name parameter. It is worth noting that most HLLs supporting pass by name parameters do not call thunks directly (like the call
above). Generally, the caller passes the address of a thunk and the subroutine calls the thunk indirectly. This allows the same sequence of instructions to call several different thunks (corresponding to different calls to the subroutine).
PassByEval: procedure(eval a:integer; eval b:integer; eval c:integer);
When you call the PassByEval
function it does not evaluate the actual parameters and pass their values to the procedure. Instead, the compiler generates thunks that will compute the value of the parameter at most one time. If the first access to an eval
parameter is a read, the thunk will compute the parameter's value and store that into a local variable. It will also set a flag so that all future accesses will not call the thunk (since it has already computed the parameter's value). If the first access to an eval
parameter is a write, then the code sets the flag and future accesses within the same procedure activation will use the written value and ignore the thunk.
Consider the PassByEval
procedure above. Suppose it takes several minutes to compute the values for the a, b,
and c
parameters (these could be, for example, three different possible paths in a Chess game). Perhaps the PassByEval
procedure only uses the value of one of these parameters. Without pass by lazy evaluation, the calling code would have to spend the time to compute all three parameters even though the procedure will only use one of the values. With pass by lazy evaluation, however, the procedure will only spend the time computing the value of the one parameter it needs. Lazy evaluation is a common technique artificial intelligence (AI) and operating systems use to improve performance.