Sub Programs
Sub Programs
Sub Programs
The basic abstraction mechanism. Functions correspond to the mathematical notion of computation input output procedures affect the environment, and are called for their side-effects pure functional model possible (but awkward) hybrid model most common: functions can have (limited) side effects.
Parameter passing
The rules that describe the binding of arguments to formal parameters, i.e. the meaning of a reference to a formal in the execution of the subprogram. By-value: formal is bound to value of actual by-reference: formal is bound to location of actual by name: formal is bound to expression for actual
Functional Programming
All parameter-passing by value no assignment. local declarations of constants only. consequence: functions have no side-effects. referential transparency: two occurrences of the same expression have the same meaning. awkward if need to describe computations with history, e.g. a random number generator.
independent of whether binding by value, by reference, or by copy-return. Functions can only have in parameters history: can assign to global variables.
Syntactic sugar
Default values for in-parameters (Ada)
function Incr (base: integer; delt : integer :=1) return integer;
Parameter passing in C
C: parameter passing by value, no semantic checks. Assignment to formal is assignment to local copy If argument is pointer, effect is similar to passing designated object by reference
void incr (int* x) { (*x) ++; } incr (&counter); /* pointer to counter*/
no need to distinguish between functions and procedures: void indicates side-effects only.
Parameter-passing in C++
Default is by-value (same semantics as C) Explicit reference parameters: void incr (int& y) { y++}; incr (counter); // compiler knows profile of incr, builds reference semantic intent indicated by qualifier: void f (const double& val); // in-parameter by reference: call cannot modify it
Parameter-passing in Java
By value only. Semantics of assignment differs for primitive types and for classes: primitive types have value semantics objects have reference semantics Consequence: methods can modify objects. No way express semantic intent on primitive types: assignment allowed, affects local copy. Can express semantic intent on objects: final means that formal is read-only.
Parameter Passing in C#
As in Java: by-value is default. For class types this means the reference is immutable, but not the object Parameter can indicate intent:
out double X ; ref int X; // uninitialized, by reference // in out, by reference
Block structure
procedure outer (x : integer) is y : boolean; procedure inner (z : integer) is x : float := 3.0; -- hides outer.x function innermost (v : integer) return float is begin return x * float (v * outer.x); -- use inner.x and outer.x end innermost; begin x := innermost (z); -- assign to inner.x end inner; begin inner (x); -- outer.x, the other one is out of scope end;
Bounded Nesting
C: no nested functions. Blocks are merged with activation record of enclosing function. Static storage available. Ada: arbitrary nesting of packages and subprograms. Packages provide static storage. early C++, Java: 3 levels: static objects, class members, entities local to a member. current C++, Java: nested classes provide arbitrary nesting
Run-time organization
Each subprogram invocation creates an activation record. Recursion imposes stack allocation (all languages today) Activation record hold actuals, linkage information, saved registers, local entities. caller: place actuals on stack, return address, linkage information, then transfer control to callee. Prologue: save registers, allocate space for locals Epilogue: place return value in register or stack position, update actuals, restore registers, then transfer control to caller. Binding of locations: actuals and locals are at fixed offsets from frame pointers complications: variable no. of actuals, dynamic objects.
Handled by caller
Return addr
Save area local local
Handled by callee
Stack pointer
Need run-time structure to locate activation record of statically enclosing scopes. Environment includes current activation record AND activation records of parent scopes.
Global linkage
Static chain: pointer to activation record of statically enclosing scope display: array of pointers to activation records does not work for function values functional languages allocate activation records on heap may not work for pointers to functions simpler if there is no nesting (C, C++, Java) can check static legality in many cases (Ada)
Static Links
Activation record hold pointer to activation record of enclosing scope. Setup as part of call prologue.
To enclosing scope To retrieve entity 3 frames out: 3 dereference operations
Display
Global array of pointers to current activation records
outermost
display
...
outer outer outer
inner inner inner inner
Subprogram parameters
type proc is access procedure (X : Integer); procedure Perform (Helper : proc) is begin proc (42); end; procedure Action (X : Integer) is procedure Proxy is begin Perform (ActionAccess); end; Proxy can see (and call) Action, therefore environment of Action ( e.g static link) Is known to Proxy. Proxy transmits to Perform both a pointer to the code for Action, and the proper static link for it. -- Access creates pair (ptr to Action , environment of Action)
simplest implementation if Env is pointer (static link) but can also be display: more efficient to retrieve non-local entities, less efficient for subprogram parameters, because array of variable size.
The environment of definition of the function must be preserved until the point of call: activation record cannot be reclaimed if it creates functions. Functional languages require more complex run-time management. Higher-order functions: functions that return (build) functions, are powerful but complex mechanisms. Imperative languages restrict their use. A function that returns a pointer to a function is a higher-order function.
Higher-order functions
Both arguments and result can be (pointers to) subprograms:
type Func is access function (x : integer) return integer; function compose (first, second : Func) return Func is begin function result (x : integer) return integer is begin return (second (first (x)); -- implicit dereference on call end; -- in C++ as well. begin return result access; -- but first and second wont exist at the point end; -- of call, so illegal in Ada.
best not to use heap, but still need indirection. Simplest : forbid it (Pascal, C) or use heap automatically (Java)