280 likes | 408 Views
Subprograms. A subprogram allows process abstraction (as opposed to data abstraction). Characteristics single entry point caller suspended until control returns from subprogram control returns to caller when subprogram terminates only if subprogram terminates normally
E N D
Subprograms • A subprogram allows process abstraction (as opposed to data abstraction). • Characteristics • single entry point • caller suspended until control returns from subprogram • control returns to caller when subprogram terminates • only if subprogram terminates normally • exceptions allow for alternate control flow • Types • Functions: return a value • Procedures: do not return a value • Predicates: are provable (or not)
Parameters • Formal parameters/parameters • in subprogram definition • Actual parameters/arguments • in subprogram call • Binding of arguments to parameters • positional (1st is bound to 1st, 2nd to 2nd, etc) • keyword (each parameter has a keyword)
Keyword parameter example (defun makePoint (&key x y) ...) (makePoint :x 3 :y 5) (makePoint :y 5 :x 3) This example is Lisp. Other languages that permit keyword arguments include Ada and Fortran95.
Default arguments • C++, Fortran95, Ada and PHP allow default argument values void example(int x=100, int y) {...} example(30) example(100,30) example(50,30) example(50,30)
Variable-length parameter lists • Some languages allow subprograms to accept a variable number of arguments. • Lisp, Scheme, C#, Java (define f (lambda (x y) ...)) f takes a list of two args (define g (lambda lst ...)) g takes a list of unspec len
Java varargs example void foo(int x, String... names) { System.out.println(“x is ”+x); for (String name:names) { System.out.println(name); } } Vararg must be last parameter.
Parameter passing modes • in: information passes in through parameter • pass by value • out: information passes out through parameter • pass by result • in-out: information passes both in and out through parameter • pass by value-result • pass by reference
Ada parameter modes(Understanding Ada, Bray & Pokrass, pg 71) There are three parameter modes: in, out and in out. Parameters of mode in are used to pass values (not variables) to a subprogram. Within the body of the subprogram, they are constants and therefore cannot be assigned values. If a parameter declaration does not inlucde an indication of its mode, in is assumed.
Out parameters are used to return values to the caller. Such parameters might be used to return the result of a calculation of a status code. No initial value need be provided by the caller. The subprogram may assign a new value to the parameter but may not refer to it in an expression. That is, the subprogram may not use the value of the parameter, although it can assign a value to it.
The third parameter mode, in out, is used to provide an initial value to the called subprogram and return a possibly updated value. A subprogram such as an array sort would use an in out parameter for the array to pass in the initial unsorted array and to pass back the same array sorted.
in mode • This is probably the most familiar and common mode. • A copy of the argument is passed to the subprogram. • Argument of subprogram can be any expression producing a value of the correct type: • currentPrecip • (currentPrecip + previousPrecip) / 2.0
pass by value examples // Java: assignment has no effect on argument // double rainfall = 2.0; // addPrecip(rainfall); public void addPrecip(double p) { p = p * 25.4; // convert from inches to mm totalPrecip += p; } // C: assignment has no effect on argument // double rainfall = 2.0; // addPrecip(rainfall); void addPrecip(double p) { p = p * 25.4; // convert from inches to mm totalPrecip += p; }
out mode • This is less familiar • Useful when a subprogram needs to “return” multiple values, but language allows only a single return value from a subprogram. • Of course, could also return a composite value, such as a tuple, like ML does by default.
Ada example // two values “returned” procedure ex(x, y: in INTEGER; s, l: out INTEGER) is begin if x<y then s = x; l = y; else s = y; l = x; end if; end ex; // Called as follows: // a : INTEGER := 5; b : INTEGER := 3; // smallest: INTEGER; largest : INTEGER; // ex(a, b, smallest, largest); // Binds smallest to 3, largest to 5
C# example // two values “returned” void ex(int x, int y, out int s, out int l) { if (x<y) { s = x; l = y; } else { s = y; l = x; } } // Called as follows: // int a=5, b=3, smallest, largest; // ex(a, b, out smallest, out largest); // Binds smallest to 3, largest to 5
Prolog example % ex(X,Y,Smallest,Largest) iff Smallest is the % smaller of X and Y, and Largest is the larger. ex(X,Y,X,Y) :- X < Y. ex(X,Y,Y,X) :- X >= Y. // Called as follows: // A=5, B=3, ex(A, B, Smallest, Largest) // Binds Smallest to 3, Largest to 5
in out mode • There are many ways to implement this: • value-return • references • pointers
Swapping routines // C – using pointers swap(int *x, int *y) { int tmp = *x; *x = *y; *y = tmp; } // Called as follows: // int a=5, b=3; // swap(&a, &b); // Binds a to 3, b to 5
// C# - pass by reference swap(ref int x, ref int y) { int tmp = x; x = y; y = tmp; } // Called as follows: // int a=5, b=3; // swap(ref a, ref b); // Binds a to 3, b to 5
// C++ - pass by reference swap(int &x, int &y) { int tmp = x; x = y; y = tmp; } // Called as follows: // int a=5; b=3; // swap(a, b); // Binds a to 3, b to 5
value vs. reference • If language gives choice, what are issues to consider between value vs. reference passing? • Should caller be able to modify value of argument? reference • Should caller be prevented from modifying value of argument? value • Is argument large & expensive to copy? reference • Is argument not an l-value? value • depends on language: Fortran manufactures a temporary variable • Will argument be referenced frequently? value • to avoid cost of reference indirection
Note about Fortran Fortran passes all parameters by reference, but does not require that every actual parameter be an l-value. If a built-up expression appears in an argument list, the compiler creates a temporary variable to hold the value, and passes this variable by reference. A Fortran subroutine that needs to modify the values of its formal parameters without modifying its actual parameters must copy the values into local variables, and modify those instead. [Scott, Programming Language Pragmatics, p. 444]
Read-only reference parameters • Modula-3 has a READONLY modifier • combine efficiency of reference parameters with the safety of value parameters • C/C++ has const modifier (creates “elaboration-time constants”, as opposed to “compile-time constants”). • C example [Scott, p 445] void append_to_log(const huge_record *r) {…} … append_to_log(&my_record); • const applies to record: r can be changed, but not *r.
const in C++ • void foo(const int& x) {…} • void foo(const int* x) {…} • void foo( int* const x) {…} • void foo(const int* const x) {…}
value-result vs. reference type t is record a, b: integer; end record; r:t; procedure foo(s : in out t) is begin r.a := r.a + 1; -- by value-result, s is distinct from r s.a := s.a + 1; -- by reference, s and r refer to same structure end foo; … r.a := 3; foo(r); put (r.a); -- does this print 4 or 5? [Scott, pg. 447]
Closures as parameters • A closure is a reference to a subprogram together with a referencing environment • [See examples from Scott, pp. 450-451]
Call-by-name • “Explicit subroutine parameters are not the only language feature that requires a closure to be passed as a parameter.” • “A call by name parameter is re-evaluated in the caller’s referencing environment every time it is used. The effect is as if the called routine had been textually expanded at the point of the call, with the actual parameter (…) replacing every occurrence of the formal parameter. • To implement call by name, Algol 60 implementations pass a hidden subroutine that evaluates the actual parameter in the caller’s referencing environment. This hidden routine is usually called a thunk. [Scott, pp. 451-452]
Function returns [457] • Restrictions on returned values: • Algol 60, Fortran: scalar value • Pascal, Modula-2: scalar or pointer • Algol 68, Ada, C: also composite type • Modula-3, Ada 95: also closure to be returned • C (no closures): function pointer • Scheme, ML: any type (incl. closure)