Professional Documents
Culture Documents
Topics
• Abstraction of control
• Methods of parameter passing
• Higher-order functions
◦ Functions as parameters
◦ Functions as results
• Exception handling
Abstraction
double P (int x) {
double z;
...
return expr;
}
• Terminology
◦ Declaration/definition
int f (int n) {return n+1;}
◦ Use
x=f(y+3);
◦ n and y+3 are the formal parameter and the actual parameter
Communication between the function and the caller
• Value returned
y = 1;
foo(y+1);
• Here, y is 8
• Here, y is 8
• Call by value
◦ Simple semantics. The body of the procedure does not need to
know how the procedure was called (referential transparency)
◦ Implementation fairly simple
◦ Call could be expensive
◦ Need for other mechanisms to communicate with the called pro-
cedure
• Call by reference
◦ Complicated semantics: Aliasing
◦ Simple implementation
◦ Call is efficient; Reference to formal parameter slightly more ex-
pensive
Call by name
• Copy rule
◦ A call to P is the same as executing the body of P after substi-
tuting the actual parameters for the formal one
• “Macro expansion”, implemented in a semantically correct way
• Appears to be simple
Call by name
int y;
void foo (name int x) {x= x + 1; }
...
y = 1;
foo(y);
• This increments y
Call by name
int y;
void fie (name int x){
int y;
x = x + 1; y = 0;
}
...
y = 1;
fie(y);
int y ;
void fie (int x ){
int y;
x = x + 1; y = 0;
}
...
y = 1;
fie(y);
• Example:
• Three declarations of x
• When f is called (via h), which x is used?
◦ Static scoping: The external x
◦ Dynamic scoping: Both would make sense
Binding rules
{int x=1;
int f(int y){
return x+y;
}
void g (int h (int b)){
int x=2;
return h(3)+x;
}
...
{int x=4;
int z=g(f);
}
}
Deep and shallow binding: Example
{int x=1;
int f(int y){
return x+y;
}
void g (int h(bool b)){
int x=2;
return h(3)+x;
}
...
{int x=4;
int z = g(f);
}
}
Closure
• Both the link to the code of the function, as well as its nonlocal
environment are passed to the function
• The procedure passed as parameter
◦ Allocates the activation record
◦ Takes the pointer to the static chain of the closure
Summary: Functions as parameters
• Shallow binding
◦ No need to do anything special
• To access x use the stack
• Use the standard structures (A-list, CRT)
• Deep binding
◦ Use some form of closure to “freeze” the scope so that it can be
reactivated later
Another example
• threshhold
◦ Selection condition for database
◦ Function older_than_threshhold: deep binding seems appro-
priate
• line_length
◦ print_person: Shallow binding seems appropriate
Another example
Deep vs. shallow binding
• Summary
◦ Dynamic scope
• Possible with deep binding
◦ Implementation with closure
• Or shallow binding
◦ No special implementation needed
◦ Static scope
• Always uses deep binding
◦ Implemented with closure
• At first glance no difference between deep and shallow binding
◦ The static scoping rules determine which nonlocal value to
use
• That is not the case: There may be dynamically several in-
stances of a block that declare a non-local name (for example
with recursion)
Returning a function: Simple case
{ int x=1
void->int F() {
int g() {
return x+1;
}
return g;
}
void->int gg = F();
int z =gg ();
}
Returning a function: Simple case
• F returns a closure
• Modify the abstract machine to manage a “call by closure” as in gg();
Returning a function: Complex case
void->int F() {
int x=1;
int g() {
return x+1;
}
return g;
}
void->int gg=F();
int z=gg();
Fig. 7.18 Functions as result void->int F () {
and stack discipline int x = 1;
int g () {
return x+1;
}
return g;
Returning a function: Complex case
}
void->int gg = F();
int z = gg();
when a function is called via a formal parameter, when a function whose value is
obtained dynamically (like gg), the static chain pointer of its activation record is
determined using the associated closure (and not the canonical rules discussed in
• F returns a closure
Sect. 5 .5 .1, which would be of no help).
The general situation, moreover, is much more complex. If it is possible to re-
• But where is the association for x after F terminates?
turn a function from the inside of a nested block, it is possible to arrange that its
evaluation environment will refer to a name that, according to stack discipline, is
going to be destroyed. Let us consider, indeed, the code in Fig. 7.18, where we
have moved the declaration of x to the inside of F. Figure 7.19 shows the activation
record arrangement when gg() is called.
When the result of F() is assigned to gg, the closure which forms its value
points to an environment containing the name x. But this environment is local to F
and will therefore be destroyed on its termination. How is it possible, then, to call
gg later than this without producing a dangling reference to x? The reply can only
be drastic: abandon stack discipline for activation records, so that they can then stay
Conclusions
• Use closure
• But the activation record remains forever
◦ Loss of stack FIFO property
• How do we then implement a “stack”?
◦ No automatic deallocation
◦ Activation record on heap
◦ Static or dynamic chain connects the record
◦ Call garbage collector when needed
Exceptions: “Structured exit”
}
catch (EmptyExcp e){write(’Empty array’);}
Example
• Simple:
◦ At the beginning of a protected block: Insert on the stack of the
caller
◦ When an exception is raised
• Remove the caller from the stack and check if this is the right
one
• If not, raise a new exception and repeat
◦ Inefficient in the most frequent case where we do not find the
handler
• Each attempt must insert and remove objects from the stack
• Better solution: Table of addresses
Exercise 1
Say what will be printed by the following code fragment written in a pseudo-
language which uses static scope; the parameters are passed by value.
{int x = 2;
int fie(int y){
x = x + y; }
{int x = 5;
fie(x);
write(x);
}
write(x);
}
Exercise 2
Say what is printed by the code in the previous exercise if it uses dynamic
scope and call by reference.
Exercise 3
State what is printed by the following fragment of code written in a pseudo-
language which uses static scope and passes parameters by reference.
{int x = 2;
void fie(reference int y){
x = x + y;
y = y + 1; }
{int x = 5;
int y = 5;
fie(x);
write(x);
}
write(x);
}
Exercise 4
State what will be printed by the following code fragment written in a
pseudo-language which uses static scope and passes its parameters by value
(a command of the form foo(w++) passes the current value of w to foo
and then increments it by one).
{int x = 2;
void fie(value int y){
x = x + y; }
{int x = 5;
fie(x++);
write(x);
}
write(x);
}
Exercise 5
State what will be printed by the following fragment of code written in a
pseudo-language which uses static scope and call by name.
{int x = 2;
void fie(name int y){
x = x + y; }
{int x = 5;
{int x = 7
}
fie(x++);
write(x);
}
write(x);
}
Exercise 6
State what will be printed by the following code written in a pseudo-language
which uses dynamic scope and call by reference.
{int x = 1;
int y = 1;
void fie(reference int z){
z =x+y+z;
}
{int y = 3;
{int x = 3 }
fie(y);
write(y);
}
write(y);
}
Exercise 7
State what will be printed by the following fragment of code written in a
pseudo-language which uses static scope and call by reference.
{int x = 0;
int A(reference int y) {
int x =2;
y=y+1;
return B(y)+x;
}
int B(reference int y){
int C(reference int y){
int x = 3;
return A(y)+x+y;
}
if (y==1) return C(x)+y;
else return x+y;
}
write (A(x));
}
Exercise 8
State what will be printed by the following code fragment written in a
pseudo-language permitting reference parameters (assume Y and J are passed
by reference).
int X[10];
int i = 1;
X[0] = 0;
X[1] = 0;
X[2] = 0;
void foo (reference int Y,J){
X[J] = J+1;
write(Y);
J++;
X[J]=J;
write(Y);
}
foo(X[i],i);
write(X[i]);
Exercise 9
State what will be printed by the following code fragment written in a
pseudo-language which allows value-result parameters:
int X = 2;
void foo (valueresult int Y){
Y++;
write(X);
Y++;
}
foo(X);
write(X);
Exercise 10
The following code fragment, is to be handed to an interpreter for a pseudo-
language which permits constant parameters:
int X = 2;
void foo (constant int Y){
write(Y);
Y=Y+1;
}
foo(X);
write(X);
int X = 2;
void foo (name int Y){
X++;
write(Y);
X++;
}
foo(X+1);
write(X);
Exercise 12
Based on the discussion of the implementation of deep binding using clo-
sures, describe in detail the case of a language with dynamic scope
Exercise 13
Consider the following fragment in a language with exceptions and call by
value-result and call by reference:
{int y=0;
void f(int x){
x = x+1; throw E; x = x+1;
}
try{ f(y); } catch E {}; write(y);
}
State what is printed by the program when parameters are passed: (i) by
value-result; (ii) by reference
Exercise 14
In a pseudo-language with exceptions, consider the following block of code: