# CS 334 Lecture 13

#### 3. Call by Name (Algol-60)

Actual parameter provides expression to formal parameter - re-evaluated whenever accessed.

Ex.

```        Procedure  swap(a, b : integer);
var temp : integer;
begin
temp := a;
a := b;
b := temp
end;
```
Won't always work, e.g.

swap(i, a[i]) with i = 1, a[1] = 3, a[3] = 17.

No way to define a correct swap in Algol-60!

Expressive power - Jensen's device:

n

To compute x = Sum for i=1 to n of Vi

```    real procedure SUM (k, lower, upper, ak);
value lower, upper;
integer k, lower, upper;
real ak;
begin
real s;
s := 0;
for k := lower step 1 until upper do
s := s + ak;
sum := s
end;
```
What is result of sum(i, 1, m, A[i])?

What about sum(i, 1, m, sum(j, 1, n, B[i,j]))?

If evaluating parameters has side-effects (e.g., read), then must know how and how many times parameter is evaluated to predict what will happen.

Therefore try to avoid call-by-name with expressions with side-effects.

Lazy evaluation is efficient implementation of call-by-name where only evaluate parameter once. Requires that there be no side-effects, since owise get diff. results.

Implement call-by-name using thunks - procedures which evaluate expressions - difficult and slow. Must pass around code for evaluating expression (including environment defined in). Can use the same THUNK's as show up in environment based interpreter.

Note different from call-by-text (which would allow capture of free vbles).

Can classify parameter passing by copying (value, result, or value-result) or definitional.

Definitional have constant, variable, procedural, and functional.

Constant parameters are treated as values, not variables - different from call-by-value.
Default for Ada in parameters.

Can think of call-by-name as definitional with expression parameter.

Note that difference in parameter passing depends on what is bound (value or address) and when it is bound.

#### Procedures and functions as parameters and return values

Already seen how to pass functional (& procedural) parameters in our interpreter using closures.

When pass function (or procedure) parameters in stack-based languages, must also pass the equivalent of a closure. In particular must pass the environment in which the function was defined. This is accomplished by passing the appropriate static pointer with the function so that can find non-local variables. Usually pass the pair (ep,ip) of environment pointer and instruction pointer as the "closure" of a procedure, when it is passed as a parameter.

Returning functions from functions is harder since defining environment may go away:

```program ret;

function a(): function (integer): integer;
var m: integer;

function addm (n: integer): integer;
begin
return (n + m)
end;

begin (* a *)
m := 5;
end; (* a *)

procedure b (g: function(integer): integer);
begin (* b *)
writeln(g(2))
end (* b *)

begin (* main *)
b(a())		(* note that a() returns a function, which is
then passed to b *)
end.```
When b(a()) is called, a() returns a function which depends on the non-local variable m, but m has gone away by the time the function is actually applied. Hence languages (like ML) which allow functions to return functions cannot use the simple stack discipline - must keep around activation records even after their associated function or procedure has returned.

## Two major problems which arise with subprograms:

side-effects

aliasing

### Side-effects:

Modifications of non-local environment

Often happens with global vbles

Also call by reference parameters, very dangerous in call-by-name.

Very disturbing in functions since can make it hard to figure out values of expressions. Example:

`        A[f(j)] := j * f(j) + j `
Makes it harder to optimize - e.g. evaluate f(j) only once.

### Aliasing:

More than one name for a variable

Most common ways of arising: global and parameter, two parameters, pointers

Example:

```        Procedure swap( var x, y: integer);
begin
x := x + y;
y := x - y;
x := x - y
end;
```

Tricky way of completing swap of x and y w/out extra space.

Doesn't always work - swap (a,a) (but does work with value-result! )

Can get similar probs with A, A[i] as parameters and pointers

Another problem: Overlap btn global vble and by-reference parameter.

Causes problems with correctness since any two vbles may refer to the same object.

Also makes it difficult to optimize if can't predict when a vble might be changed.

If no aliasing, can't detect difference btn call-by-reference and call-by-value-result.

• But not semantically equivalent if aliasing is possible.
Leads to problems in Ada where language definition does not specify whether in-out parameters are to be implemented by reference or value-result.

(Illegal program if it makes a difference - but not detectable!)

Unfortunately Ada doesn't enforce no aliasing.

Therefore possible problems with in out parameters.

Euclid (variant of Pascal) designed to write verifiable programs.

• Attempted to eliminate aliasing.

• Unfortunately some can only be caught at run-time, e.g. p(A[i], A[j]). Legality assertions generated to check run-time problems.

• Global vbles had to be explicitly imported to avoid problems

i.e. treated as implicit parameters

## Correspondence Principle

Each parameter mechanism corresponds to declaration in language:
• constant parameter: constant def - value bound to identifier.

• variable parameter: variable renaming definition - new name given to old variable

• value parameter: new variable declaration w/ initialization

• procedure parameter: procedure declaration

Correspondence Principle: For each form of declaration there exists a corresponding parameter mechanism, and vice-versa.

E.g., constant, variable (def. & declaration), procedure & function, type(?)

## Problems with writing large programs:

Wulf and Shaw: Global Variables Considered Harmful (1973)
1. Side effects - hidden access

2. Indiscriminant access - can't prevent access - may be difficult to make changes later

3. Screening - may lose access via new declaration of vble

4. Aliasing - control shared access to prevent more than one name for reference variables.

### Characteristics of solution:

1. No implicit inheritance of variables

2. Right to access by mutual consent

4. Provide different types of access (e.g. read-only)

5. Decouple declaration, name access, and allocation of space. (e.g. scope indep of where declared, similarly w/allocation of space - like Pascal new)

## Abstract Data Types

(Major thrust of programming language design in 70's)

Package data structure and its operations in same module - Encapsulation

Data type consists of set of objects plus set of operations on the objects of the type (constructors, inspectors, destructors).

Want mechanism to build new data types (extensible types).

Should be treated same way as built-in types.

Representation should be hidden from users (abstract).

Users only have access via operations provided by the ADT.

Distinguish between specification and implementation.

### Specification:

Book states language should provide:

Method for defining data type and the operations on that type (all in same place). The definitions should not depend on any implementation details. The definitions of the operations should include a specification of their semantics.

Provides user-interface with ADT.

Typically includes

1. Data structures: constants, types, & variables accessible to user (although details may be hidden)

2. Declarations of functions and procedures accessible to user (bodies not provided here).

May also include axioms specifying behavior "promised" by any implementation. The following is an algebraic specification of behavior (see text for details).

Ex: pop(push(S,x)) = S,

if not empty(S) then push(pop(S), top(S)) = S

Data + Operations (+ possibly equations) = Algebra

### Implementation (Representation):

Again from text:

Method for collecting the implementation details of the type and its operations (in one place), and of restricting access to these details by programs that use the data type.

Usually not accessible to user.

Provides details on all data structures (including some hidden to users) and bodies of all operations.

Note that ADT methodology is orthogonal to top-down design

• Partition first into modules corresponding to ADT's.

• Use top-down within ADT's and in larger programs using ADT's

How to represent ADT's in programming languages?

Three predominant concerns in language design:

• Simplicity of design

• Application of formal techniques to specification & verification

• Keep down lifetime costs

Reusable modules to represent ADT's quite important.

• Separate (but not independent) compilation.

• Want to maintain type checking

• Control over export and import of names (scope)

Examine implementation in Simula 67, Ada, Modula 2, Clu, and ML..

### Simula 67

Derived from Algol 60. Simulation language.

Provided notion of class.

• Each kind of object being simulated belongs to a class.
• Objects called class instances.
• Class similar to type but includes procedures, functions, and variables.
Ex.:
```class vehicle(weight,maxload);
begin
integer licenseno;      (* attributes of class instance *)
Boolean procedure tooheavy;
tooheavy := weight + load > maxload;
load := 0;      (* initialization code *)
end
```
Refer to objects through references:
```    ref(vehicle) rv, pickup;
rv1:- new vehicle(2000,2500);
pickup:- rv1;       (* special assignment via sharing *)
if pickup.tooheavy then ...
```
Notice that attributes are available to all users.

Representation not hidden.

Come back to discuss subclasses later when discussing object-oriented languages.

#### Intermezzo: What are problems with defining a new type in terms of an old?

E.g., represent rationals as records (or ordered pairs) of integers.

1. Representation might have several values that do not correspond to any values of the desired type (e.g., (3,0)).

2. Representation might have multiple values corresponding to the same abstract value (e.g., (1,2), (2,4), etc.)

3. Values of the new type can be confused with values of the representation type.

Abstract data type is one that is defined by group of operations (including constants) and (possibly) a set of equations. Set of values only defined indirectly as those values which can be generated by ops, starting from constructors or constants.

E.g., Stack defined by EmptyStack, push, pop, top, and empty operations and equations.

```   pop(push(fst,rest)) = rest,
top(push(fst,rest)) = fst,
empty(EmptyStack) = true,
empty(push(fst,rest)) = false,
etc.```
Key is representation is hidden.

Designed via a U.S. DOD competition

Packages used to define abstract data types.

Package together type, operations (& state) and hide rep.

Provides support for parameterized packages (polymorphism)

```package <package-name> is
--  declarations of visible types, variables, constants, and subprograms
private
--  complete definitions of private types and constants
end <package-name>;

package body <package-name> is
-- definitions of local variables, types, and subprograms, and complete bodies for
-- subprograms declared in the specification part above.  Code for initialization
-- and exception handlers
end <package-name>;
```
Sample Program:

```package VECT_PACKAGE is  -- declarations only
type REAL_VECT is array (INTEGER range <>) of float;
function SUM(V: in REAL_VECT) return FLOAT;
procedure VECT_PRODUCT(V1,V2 : in REAL_VECT) return                                 FLOAT;
function MAX(V: in REAL_VECT) return FLOAT;
end VECT_PACKAGE ;

package body VECT_PACKAGE is  -- details of implementation
function SUM(V: in REAL_VECT) return FLOAT is
TEMP : FLOAT := 0.0;
begin
for I in V'FIRST..V'LAST loop
TEMP:= TEMP + V(I);
end loop;
return TEMP;
end;
-- definitions of VECT_PRODUCT and MAX subprograms would appear here
end VECT_PACKAGE ;

with VECT_PACKAGE, TEXT_IO; -- used to make separately compiled package visible
procedure MAIN is
use VECT_PACKAGE, TEXT_IO;  -- eliminates need for qualifiers
package INT_IO is new INTEGER_IO(INTEGER); --instantiation of generic packages
package REAL_IO is new FLOAT_IO(FLOAT);
use INT_IO, REAL_IO;
K: INTEGER range 0..99;
begin
loop
GET(K);
exit when K<1;
declare         -- start of block
A : REAL_VECT(1..K);  -- provides subscript bounds
begin
for J in 1..K loop
GET(A(J));
PUT(A(J));
end loop;
PUT("SUM = ");
PUT(SUM(A));      -- uses package function
end; -- of block
end loop;
end MAIN ;
```
SOPHISTICATED (generic) STACK EXAMPLE

Stack represented internally in package (closer to object-oriented than get w/ Modula 2)

```generic
length : Natural := 100;      -- generic parameters
type element is private;
-- only assignment and tests for = may be done on objects of "private" type
-- "limited private" is also available.
package stack is
procedure push (X : in element);
procedure pop (X: out element);
function empty return boolean;
stack_error : exception;
end stack;

package body stack is
space   : array (1..length) of element;
top : integer range 0..length := 0;

procedure push (X : in element) is
begin
if full()  then
raise stack_error;
else
top := top + 1;
space(top) := X;
end if;
end push;

procedure pop (X: out element) is
begin
if empty() then
raise stack_error;
else
X := space(top);
top := top - 1;
end if;
end pop;

function empty return boolean is
begin
return (top = 0);
end;

function full return boolean is
begin
return (top = length);
end;

end stack;
```

Notice: Data structure of stack is entirely hidden from user -

there is no object of type stack available to user.

How to use:

```    package stack1 is new stack(20,integer);
package stack2 is new stack(100, character);
-- Note that this initializes length in both cases to 0
use stack2;
stack1.push(5)
if not stack1.empty() then
stack1.pop(Z);
endif;
push('z');
```
Note: Package definition is very much like that of a record with procedures allowed as (non-updateable) fields. E.g.
```        stack =  package
push : procedure (X : in element);
pop : procedure (X: out element);
empty : function return boolean;
stack_error : exception;
end package;
```

One of two key ideas behind object-oriented programming.