Chapter 9: Subprograms • • • • • • Introduction Fundamentals of Subprograms Local Referencing Environments Parameter-Passing Methods Type Checking Parameters Design Issues for Functions 9-1 Introduction • Two fundamental abstraction facilities – Process abstraction • Emphasized from early days->subprogram – Data abstraction • Emphasized in the1980s-> Class (ch 11 & 12) • Benefits of subprogram – Process abstraction: • The procedure name like “sort” conveys the intent of the procedure. • focus on what; – implementation hiding: • Only procedures needs to be modified. • easy to modify; – modular program: easy to manage a large program; – libraries: extending a language 9-2 Fundamentals of Subprograms • Each subprogram has a single entry point • A subprogram call is an explicit request that the subprogram be executed • The calling program is suspended during execution of the called subprogram • Control always returns to the caller when the called subprogram’s execution terminates 9-3 Procedures and Functions • There are two categories of subprograms – Procedures are collection of statements that define parameterized computations • treated as atomic statements, e.g., read (ch). – Functions structurally resemble procedures but are semantically modeled on mathematical functions • like operators, which return a result. • called from within expressions, e.g., r*sin(angle). 9-4 Basic Definitions • A subprogram definition describes the interface to and the actions of the subprogram abstraction • A subprogram header is the first part of the definition, including the name, the kind of subprogram, and the formal parameters – Ada: – C: Procedure Adder (parameters) void adder (parameters) • The protocol is a subprogram’s parameter profile (including the number, order, and types of its parameters), and, if it is a function, its return type • A subprogram declaration provides the protocol, but not the body, of the subprogram • Function declarations in C and C++ are called prototypes, and often placed in header files. 9-5 Actual/Formal Parameter • A formal parameter is a dummy variable listed in the subprogram header and used in the subprogram • An actual parameter represents a value or address used in the subprogram call statement • Positional correspondence – the first actual parameter is bound to the first formal parameter, and so forth – Safe and effective • Keyword correspondence – The name of the formal parameter to which an actual parameter is to be bound, is specified with the actual parameter – Parameters can appear in any order – Python example: sumer(length = my_len, list = my_array) 9-6 Formal Parameter Default Values • In certain languages (e.g., C++, Ada), formal parameters can have default values (if not actual parameter is passed) – In C++, default parameters must appear last because parameters are positionally associated – Example: float compute_pay(float income, float tax_rate, int exemptions = 1) pay = compute_pay(20000.0, 0.15); 9-7 Local Referencing Environments • Local variables can be stack-dynamic (bound to storage) – Advantages • Support for recursion • Storage for locals is shared among some subprograms – Disadvantages • Allocation/de-allocation, initialization time • Indirect addressing • Subprograms cannot be history sensitive • Local variables can be static – retain their values between activations (Ch 10); the lifetime of a static variable is the entire computation. – Storage for them is allocated statically at compile time; No run-time overhead – More efficient (no indirection) – Cannot support recursion – declared by the keyword static in C. 9-8 Example of static variables • Consider the following declaration: • int f(int n) { static int count = 0; int result; count = count + 1; if (n == 0) result = 1; else result = n * f(n-1); return result; } A trace showing the values of variables for the call f(3) -> f: n=3; count = 0 -> f: n=2; count = 1 -> f: n=1; count = 2 -> f: n=0; count = 3 <- f: n=0; count = 4; result = <- f: n=1; count = 4; result = <- f: n=2; count = 4; result = <- f: n=3; count = 4; result = 1 1 2 6 9-9 Parameter Passing Methods • Ways in which parameters are transmitted to and/or from called subprograms – Pass-by-value – Pass-by-result – Pass-by-value-result – Pass-by-reference – Pass-by-name 9-10 Models of Parameter Passing 9-11 Pass-by-Value (In Mode) • The value of the actual parameter is used to initialize the corresponding formal parameter. • This method is normally used in Pascal, C, and C#. • Example: In the call square (2+3) -> x := 2+3; square := x*x; return 25 • Implementation – Normally implemented by copying – Require additional storage – Storage and copy operations can be costly • This method cannot change the value of the actual parameters 9-12 Pass-by-Result (Out Mode) • passed by result: – no value is transmitted to the subprogram – the formal parameter acts as a local variable; its value is transmitted to caller’s actual parameter when control is returned to the caller – Require extra storage location and copy operation – in C#: “out” is specified in formal and actual parameters • Example void Fixer(out int x, out int y) {x = 17; y=35;} … f.Fixer(out a, out b); • Potential problem: sub(p1, p1); whichever formal parameter is copied back last will represent the current value of p1 9-13 Pass-by-Value-Result (inout Mode) • A combination of pass-by-value and pass-byresult • The actual are initially copied into the formals, and the formals are eventually copied back out to the actuals. • Formal parameters have local storage • Sometimes called pass-by-copy • In Ada 95, all scalars are passed-by-copy – Support three parameters: In, out, in out • Disadvantages: – Those of pass-by-result – Those of pass-by-value 9-14 Pass-by-Reference (Inout Mode) • Pass an access path – A formal parameter becomes a synonym for the location of an actual parameter; • In C# – Pass-by-reference is specified by preceding both a formal parameter and its actual parameter with ref – In Pascal, using “var” with formals (see the next page) • achieved in C using pointers. – The function is defined as follows: void swapc(int *px, int *py) {int z; z = *px; *px = *py; *py = z; } – The procedure call should pass the pointer such as swapc(&a, &b). 9-15 Pass-by-Reference (cont) • It is achieved in Pascal using the keyword “var”. • Example: procedure swap (var x: integer; var y: integer); var z: integer; begin z := x; x := y; y := z; end; • A call swap (i, A[i]) does the following: make the location of x the same as that of i; make the location of y the same as that of A[i]; z :=x; x:=y; y:=z; • If i is 2 and A[2] = 99; the effect of the call will be: z: = 2; i:=99; A[2] := z => changed 9-16 Pass-by-Reference (cont) • Advantage – Passing process is efficient (no copying and no duplicated storage) • Disadvantages – Slower accesses (compared to pass-by-value) to formal parameters, due to indirect addressing – Potentials for un-wanted side effects, which changes the actual parameters – Un-wanted aliases • Example (in C++) void fun(int &first, int &second) The call: fun(total, total) 9-17 Pass-by-Name (Inout Mode) • By textual substitution • Allows flexibility in late binding – Not at the time of the subprogram call, but when the formal is assigned or referenced • Example (in Pascal): Consider the procedure swap in page 16 without “var”. • A call swap(i, A[i]) yields: z :=i; i:=A[i]; A[i]:=z; • If i is 2 and A[2] = 99, the effect of the call will be: z: = 2; i:=99; A[i] := z => A[99] is affected, not A[2] -> dynamic binding • It is used in Algol 60 and achieves lexical scope by renaming locals. 9-18 Type Checking Parameters • Considered very important for reliability • Pascal, FORTRAN 90, Java, and Ada: it is always required • ANSI C and C++: choice is made by the user – Example of avoiding type checking: double sin(x) double x; {…..} • Relatively new languages Perl, JavaScript, and PHP do not require type checking, since variables (and formal parameters) are typeless. 9-19 Multidimensional Arrays as Parameters • If a multidimensional array is passed to a subprogram and the subprogram is separately compiled, the compiler needs to know the declared size of that array to build the storage mapping function 9-20 Multidimensional Arrays as Parameters: C and C++ • Programmer is required to include the declared sizes of all but the first subscript in the actual parameter, to compute the address • Example: void fun(int matrix[][10]) {…} • Disallows writing flexible subprograms • Solution: pass a pointer to the array and the sizes of the dimensions as other parameters; the user must include the storage mapping function in terms of the size parameters • Example: void fun(float * mat_ptr, int num_row, int num_col); .. *(mat_ptr + (row *num_col) + col) = x; 9-21 Multidimensional Arrays as Parameters: Pascal and Ada • Pascal – Not a problem; declared size is part of the array’s type • Ada – Constrained arrays - like Pascal – Unconstrained arrays - declared size is part of the object declaration • Java and C# – Similar to Ada – Arrays are objects; they are all single-dimensioned, but the elements can be arrays – Each array inherits a named constant (length in Java, Length in C#) that is set to the length of the array when the array object is created 9-22 Design Issues for Functions • Are side effects allowed? – Ada: Parameters should always be in-mode to reduce side effect • What types of return values are allowed? – Most imperative languages restrict the return types – C allows any type except arrays and functions – C++ is like C but also allows user-defined types – Ada allows any type – Java and C# do not have functions but methods can have any type 9-23