CSE 505 Lecture Notes:

Parameter Passing - Overview

October 2001


Introduction

We'll encounter these issues in all of the languages we study, so it's worth setting out the basics now.

Standard techniques used for argument passing:

(and call-by-equality in constraint languages)

call by value: copy going into the procedure

call by result: copy going out of the procedure

call by value result: copy going in, and again going out

call by reference: pass a pointer to the actual parameter, and indirect through the pointer

call by name: re-evaluate the actual parameter on every use. For actual parameters that are simple variables, this is the same as call by reference. For actual parameters that are expressions, the expression is re-evaluated on each access. It should be a runtime error to assign into a formal parameter passed by name, if the actual parameter is an expression. Implementation: use anonymous function ("thunk") for call by name expressions

efficiency of call by reference -- large arrays

Fortran uses call by reference
insecurities in early FORTRANs -- passing a constant

Algol 60 has call by name, call by value

Ada uses different designations: IN, OUT, IN OUT:

Lisp and Smalltalk use call-by-value with pointer semantics. Java uses call-by-value -- with just copying for primitive types, and pointer semantics for objects.

An important related concept: aliasing. Two variables are aliased if they refer to the same storage location. A common way that aliasing can arise is using call by reference. A formal parameter can be aliased to a nonlocal variable, or two formal parameters can be aliased.

In a functional programming language, call by value is equivalent to applicative order evaluation. Call by name is equivalent to normal order evaluation. (It always gives the same results as lazy evaluation, but lazy evaluation may be faster.)


Example 1: illustrates call by value, value-result, reference

begin integer n; procedure p(k: integer); begin n := n+1; k := k+4; print(n); end; n := 0; p(n); print(n); end; Note that when using call by reference, n and k are aliased.

Output:

call by value: 1 1 call by value-result: 1 4 call by reference: 5 5

Example 2: Call by value and call by name

begin integer n; procedure p(k: integer); begin print(k); n := n+1; print(k); end; n := 0; p(n+10); end; Output: call by value: 10 10 call by name: 10 11

Example 3: Call by value and call by name (with evaluation errors)

begin integer n; procedure p(k: integer); begin print(n); end; n := 5; p(n/0); end; Output: call by value: divide by zero error call by name: 5

Example 4: Non-local references

procedure clam(n: integer); begin procedure squid; begin print("in procedure squid -- n="); print(n); end; if n<10 then clam(n+1) else squid; end; clam(1); Output: in procedure squid -- n=10

Example 5: Procedures as parameters

To pass a procedure as a parameter, the system passes a closure: a reference to the procedure body along with a pointer to the environment of definition of the procedure. begin procedure whale(n: integer, p: procedure); begin procedure barnacle; begin print("in procedure barnacle -- n="); print(n); end; print("in procedure whale -- n="); print(n); p; if n<10 then begin if n=3 then whale(n+1,barnacle) else whale(n+1,p) end end; procedure limpet; begin print("in procedure limpet"); end; whale(1,limpet); end; Output: in procedure whale -- n=1 in procedure limpet in procedure whale -- n=2 in procedure limpet in procedure whale -- n=3 in procedure limpet in procedure whale -- n=4 in procedure barnacle -- n=3 in procedure whale -- n=5 in procedure barnacle -- n=3 in procedure whale -- n=6 in procedure barnacle -- n=3 in procedure whale -- n=7 in procedure barnacle -- n=3 in procedure whale -- n=8 in procedure barnacle -- n=3 in procedure whale -- n=9 in procedure barnacle -- n=3 in procedure whale -- n=10 in procedure barnacle -- n=3 Similar effects can be achieved by passing labels as parameters.