FUNCTIONS 1
OUTLINE Basic Terminology Function Call and Return Parameters Parameter Passing Mechanisms Activation Records Recursive Functions Run Time Stack Function Declaration and Call in Clite Completing the Clite Type System Semantics of Call and Return Formal Treatment of Types and Semantics
BASIC TERMINOLOGY Value-returning functions: known as non-void functions/methods in C/C++/Java called from within an expression. e.g., x = (b*b - sqrt(4*a*c))/2*a Non-value-returning functions: known as procedures in Ada, subroutines in Fortran, void functions/methods in C/C++/Java called from a separate statement. e.g., strcpy(s1, s2);
EXAMPLE 1: FUNCTIONS IN C/C++ int h, i; void B(int w) { int j, k; i = 2*w; w = w+1; void A(int x, int y) { bool i, j; B(h); int main() { int a, b; h = 5; a = 3; b = 2; A(a, b);
PARAMETERS Definitions An argument is an expression that appears in a function call. A parameter is an identifier that appears in a function declaration. In Example 1 The call A(a, b) has arguments a and b. The function declaration A has parameters x and y.
PARAMETER-ARGUMENT MATCHING Usually by number and by position. I.e., any call to A must have two arguments, and they must match the corresponding parameters types. Exceptions: Perl parameters aren t declared in a function header. parameters are available in an array @_, and are accessed using a subscript on this array. Ada arguments and parameters can be linked by name. E.g., the call A(y=>b, x=>a) is the same as A(a, b)
PARAMETER PASSING MECHANISMS By value By reference By value-result By result By name
PASS BY VALUE Compute the value of the argument at the time of the call and assign that value to the parameter. E.g., in the call A(a, b) in Ex. 1, a and b are passed by value. values of parameters x and y become 3 and 2, respectively when the call begins. Passing by value doesn t normally allow the called function to modify an argument s value. All arguments in C and Java are passed by value. But references can be passed to allow argument values to be modified. E.g., void swap(int *a, int *b) {
PASS BY REFERENCE Compute the address of the argument at the time of the call and assign it to the parameter. Example: Since h is passed by reference, its value changes during the call to B. int h, i; void B(int* w) { int j, k; i = 2*(*w); *w = *w+1; void A(int* x, int* y) { bool i, j; B(&h); int main() { int a, b; h = 5; a = 3; b = 2; A(&a, &b);
PASS BY VALUE-RESULT AND RESULT Pass by value at the time of the call and/or copy the result back to the argument at the end of the call. E.g., Ada s in out parameter can be implemented as valueresult. Value-result is often called copy-in-copy-out. Reference and value-result are the same, except when aliasing occurs. That is, when: the same variable is both passed and globally referenced from the called function, or the same variable is passed for two different parameters.
PASS BY NAME Textually substitute the argument for every instance of its corresponding parameter in the function body. Originated with Algol 60 (Jensen s device), but was dropped by Algol s successors -- Pascal, Ada, Modula. Exemplifies late binding, since evaluation of the argument is delayed until its occurrence in the function body is actually executed. Associated with lazy evaluation in functional languages (see, e.g., Haskell discussion later).
ACTIVATION RECORDS A block of information associated with each function call, which includes: parameters and local variables Return address Saved registers Temporary variables Return value Static link - to the function s static parent Dynamic link - to the activation record of the caller Also known as Stack Frame.
RECURSIVE FUNCTIONS A function that can call itself, either directly or indirectly, is a recursive function. E.g., int factorial (int n) { if (n < 2) return 1; else return n * factorial(n-1); self-call
RUN TIME STACK A stack of activation records (frames). Each new call pushes an activation record, and each completing call pops the topmost one. So, the topmost record is the most recent call, and the stack has all active calls at any run-time moment. For example, consider the call factorial(3). This places one activation record onto the stack and generates a second call factorial(2). This call generates the call factorial(1), so that the stack gains three activation records.
STACK ACTIVITY FOR THE CALL FACTORIAL(3) n 3 n 3 n 3 n 3 n 3 n 2 n 2 n 2 n 1 First call Second call Third call returns 1 Second call returns 2*1=2 First call returns 3*2=6
STACK ACTIVITY FOR PROGRAM IN EX. 1 (LINKS NOT SHOWN) int h, i; void B(int w) { int j, k; h i undef undef h 5 i undef h 5 i 10 i = 2*w; w = w+1; void A(int x, int y) { bool i, j; B(h); a 3 b 2 Activation of main a 3 b 2 x y 3 2 i undef j undef a 3 b 2 x y 3 2 i undef j undef int main() { int a, b; main calls A w 5 j undef k undef h = 5; a = 3; b = 2; A(a, b); A calls B
FUNCTION IMPLEMENTATIONS 17
FUNCTION DECLARATION AND CALL Example Clite Program : int h, i; void B(int w) { int j, k; i = 2*w; w = w+1; void A(int x, int y) { bool i, j; B(h); int main() { int a, b; h = 5; a = 3; b = 2; A(a, b);
CONCRETE SYNTAX Functions and Globals (new elements underlined) Program { Type Identifier FunctionOrGlobal MainFunction Type int boolean float char void FunctionOrGlobal ( Parameters ) { Declarations Statements Global Parameters [ Parameter {, Parameter ] Global {, Identifier ; MainFunction int main ( ) { Declarations Statements
CONCRETE SYNTAX (CONT D) Function Calls (new elements underlined) Statement ; Block Assignment IfStatement WhileStatement CallStatement ReturnStatement CallStatement Call ; ReturnStatement return Expression ; Factor Identifier Literal ( Expression ) Call Call Identifier ( Arguments ) Arguments [ Expression {, Expression ]
ABSTRACT SYNTAX Program = Declarations globals; Functions functions Functions = Function* Function = Type t; String id; Declarations params, locals; Block body Type = int boolean float char void Statement = Skip Block Assignment Conditional Loop Call Return Call = String name; Expressions args Expressions = Expression* Return = Variable target; Expression result (target is the name of the function itself) Expression = Variable Value Binary Unary Call
ABSTRACT SYNTAX FOR A CLITE PROGRAM EX. 1 Declarations Program globals body Functions h i Function int main Function void A a b Call A(a,b); Function void B params locals body x y i j w j k Block i = 2 * w; w = w + 1;
COMPLETING THE CLITE TYPE SYSTEM Type Rule 1 Every function and global id must be unique. E.g., h, i, A, B, and main are unique. Type Rule 2 Every function s params and locals must have mutually unique id s. E.g., function A s locals and params have id s x, y, i, and j. Type Rule 3 Every statement in the body of each function must be valid with respect to the function s locals, params, and visible globals. Note: Combine with type rules for Clite (type systems) for the different statement types.
TYPE RULES FOR CALL AND RETURN Type Rule 4 A non-void function (except main) must have a Return statement, whose Expression must be the same type as the function. Type Rule 5 A void function cannot have a Return. Type Rule 6 Every Call Statement must identify a void function, and every Call Expression must identify a non-void function.
TYPE RULES FOR CALL AND RETURN (CONT D) Type Rule 7 Every Call must have the same number of arguments as the number of params in the function it identifies. Each such argument must have the same type as its corresponding param, reading from left to right. Type Rule 8 Every Call to a non-void function has the type of that function. The Expression in which the Call appears must be valid according to Type Rules for expressions of Clite. 25
TYPE RULES FOR SAMPLE PROGRAM Type Rule 4 No return statement appears in main. Type Rule 5 No return statement appears in A or B. Type Rule 6 The Call Statement A(a,b) identifies the function void A(int x, int y) Type Rule 7 The Call Statement A(a,b) has two arguments, whose types (int) are the same as the parameters x and y. Type Rule 8 is not applicable. int h, i; void B(int w) { int j, k; i = 2*w; w = w+1; void A(int x, int y) { bool i, j; B(h); int main() { int a, b; h = 5; a = 3; b = 2; A(a, b);
EXAMPLE WITH NON-VOID FUNCTIONS Computing a Fibonacci Number int fibonacci (int n) { int fib0, fib1, temp, k; fib0 = 0; fib1 = 1; k = n; while (k > 0) { temp = fib0; fib0 = fib1; fib1 = fib0 + temp; k = k - 1; return fib0; int main () { int answer; answer = fibonacci(8);
TYPE RULES FOR FIBONACCI PROGRAM Type Rule 4 return fib0; appears in int fibonacci (int n) Type Rule 5 is not applicable Type Rule 6 The Call fibonacci(8) identifies the non-void function int fibonacci (int n) Type Rule 7 The Call fibonacci(8) has one argument, whose type (int) is the same as that of the parameter n. Type Rule 8 The Expression in which the Call fibonacci(8) appears is valid. int fibonacci (int n) { int fib0, fib1, temp, k; fib0 = 0; fib1 = 1; k = n; while (k > 0) { temp = fib0; fib0 = fib1; fib1 = fib0 + temp; k = k - 1; return fib0; int main () { int answer; answer = fibonacci(8);
SEMANTICS OF CALL AND RETURN Meaning Rule 1 The meaning of a Call c to Function f has the following steps: 1. Make an activation record and add f s params and locals to it. 2. Evaluate c s args and assign those values to f s corresponding params. 3. If f is non-void, add a result variable identical with f s name and type. 4. Push the activation record onto the run-time stack. 5. Interpret f s body. 6. Pop the activation record from the stack. 7. If f is non-void, return the value of the result variable to the Expression where c appears.
EXAMPLE PROGRAM TRACE Calling Returning Visible State main <h,undef>, <i,undef>, <a,undef>, <b,undef> A <h,5>, <x,3>,<y,2>, <i,undef>, <j,undef> B <h,5>, <i,undef>,<w,5>, <j,undef>, <k,undef> B <h,5>, <i,10>,<w,6>, <j,undef>, <k,undef> A <h,5>, <x,3>,<y,2>,<i,undef>, <j,undef> main <h,5>, <i,10>, <a,3>, <b,2> int h, i; void B(int w) { int j, k; i = 2*w; w = w+1; void A(int x, int y) { bool i, j; B(h); int main() { int a, b; h = 5; a = 3; b = 2; A(a, b);
NON-VOID FUNCTIONS Meaning Rule 2 The meaning of a Return is the result of assigning the value of the result Expression to the result variable. Meaning Rule 3 The meaning of a Block is the aggregated meaning of its Statements when applied to the current state, up to and including the point where the first Return is encountered. Note: The first Return encountered terminates the body of a called function.
EXAMPLE PROGRAM TRACE Calling Returning Visible State main fibonacci fibonacci main <answer,undef> <n,8>, <fib0,undef>, <fib1,undef>, <temp,undef>, <k,undef>, <fibonacci,undef> <n,8>, <fib0,21>, <fib1,34>, <temp,13>, <k,0>, <fibonacci,undef> <answer,21> int fibonacci (int n) { int fib0, fib1, temp, k; fib0 = 0; fib1 = 1; k = n; while (k > 0) { temp = fib0; fib0 = fib1; fib1 = fib0 + temp; k = k - 1; return fib0; int main () { int answer; answer = fibonacci(8);
SIDE-EFFECTS REVISITED Side-effects can occur in Clite. E.g., in Example 1, a call to B alters the value of global variable i. If B had been non-void, this side-effect could have subtly affected an expression like B(h)+i. In the semantics of Clite, evaluation of operands in a Binary is left-to-right. Thus, the result of B(h)+i is always the same, and always different from i+b(h). Side-effects often create distance between mathematics and programming. E.g., Clite expressions with + are clearly not commutative, while in mathematics they are.
FORMAL TREATMENT OF TYPES AND SEMANTICS The type map for a function f, tm f, is a set of pairs and triples, representing global variables (tm G ), functions (tm F ), f s parameters, and f s locals. E.g., for the program in Example 1:
TYPING FUNCTION The function typing creates type maps for each individual function f in a program with globals G and functions F.
VALIDITY OF A CLITE PROGRAM A program is valid if its global variables and function declarations are valid, and each function is valid with respect to their type maps.
VALIDITY OF A CLITE FUNCTION A function is valid if 1) its parameters and locals have unique names, 2) its statements are valid in its type map, and 3) it contains (does not contain) a return statement if it is a non-void (void) function. V : Function TypeMap B V( f,tm) = V( f.paramsè f.locals)ùv( f.body,tm)ù ( f.t ¹ void Ù f.id ¹ mainù$s Î f.body : s is a ReturnÚ (f.t = void Ú f.id = main)ùø$s Î f.body : s is a Return), where tm = typing(g, F, f ) E.g., for the Clite program in Ex.1, we need to establish that V(A,tm A ),V(B,tm B ), and V(main,tm main ).
VALIDITY OF A CLITE CALL AND RETURN Validity of most Clite statements was defined in previous lecture. Validity of a Call and a Return is defined below:
FORMALIZING THE SEMANTICS OF CLITE Memory ( ), Environment ( ) and State ( ): The State of a function f, f, is a triple f a where a addresses the top of the run-time stack, is a set of address-value pairs, and f has f s visible variables and their addresses.
ALLOCATE AND DEALLOCATE FUNCTIONS allocate changes the state by adding a group of variable-address pairs to it. deallocate removes such a group. allocate(d 1,d 2,...,d k,s) = g' m' a' w here g'= g È d 1.v.id,a, d 2.v.id,a +1,..., d k.v.id,a + k -1 m'= mè a'= a + k { { a,undef, a +1,undef,..., a + k -1,undef deallocate(d 1,d 2,...,d k,s) = g' m' a' w here g'= g - d k.v.id,a, d k-1.v.id,a +1,..., d 1.v.id,a + k -1 m'= mè a'= a - k { { a,unused, a +1,unused,..., a + k -1,unused
CALLING A VOID FUNCTION Meaning Rule 1 in functional form, skipping temporarily the returned result:
CALL/RETURN FOR A NON-VOID FUNCTION The Call returns a Value; the Return identifies it:
MEANING OF A BLOCK Since a block can contain a Return, it must exit as soon as the return is encountered (Meaning Rule 3). Here is the functional definition.