IA010: Principles of Programming Languages
5. Subroutines
Jan Obdržálek obdrzalek@fi.muni.cz
Faculty of Informatics, Masaryk University, Brno
IA010 5. Subroutines 1 Subroutines
Subprograms, functions, procedures, . . .
• principal mechanism for control abstraction • details of subroutine’s computation are replaced by a statement that calls the subroutine • increases readability: emphasizes logical structure, while hiding the low-level details • facilitate code reuse, saving • memory • coding time • subroutines vs OOP methods: • differ in the way they are called • methods are associated with classes and objects
IA010 5. Subroutines 2 Outline
Fundamentals of subroutines
Parameter-passing methods
Overloaded and generic subroutines
Functions – specifics
Coroutines
IA010 5. Subroutines 3 Fundamentals of subroutines
IA010 5. Subroutines 4 Subroutine characteristics
• each subroutine has a single entry point • the calling program unit is suspended during subroutine execution (so only one subroutine is in execution at any given time) • control returns to the caller once subroutine execution is terminated • alternatives: • coroutines • concurrent units
IA010 5. Subroutines 5 Basic definitions
• subroutine definition – describes the interface and actions • subroutine call – an explicit request for the subroutine to be executed • active subroutine – has been executed, but has not yet completed its execution • subroutine header – part of the definition, specifies: • the kind of the subroutine (function/procedure) • a name (if not anonymous) • a list of parameters • parameter profile – the number, order and types of formal parameters • protocol – parameter profile + return type
IA010 5. Subroutines 6 Procedures and functions procedures • do not return values • in effect define new statements • as functions: can return a value using • global variables • two-way communication through parameters functions • return values • function call is, in effect, replaced by the return value • as procedures: e.g. using the void return type • modelled after mathematical function (the model is faithful if no side-effects are allowed)
IA010 5. Subroutines 7 Parameters
Mechanism for passing data between a subroutine and its caller. (another option: through global variables) formal parameters (parameters) • specified in the subroutine header • sometimes called dummy variables actual parameters (arguments) • specified in the subroutine call statement binding of actual parameters to formal parameters • positional parameters – by position (first to first, . . . ) • keyword parameters – the formal parameter name is explicitly given in a call (in any order) attack(weapon = my_weapon, force = my_force) • when combined (e.g. Ada, Fortran95+, Python) once a keyword parameter appears, all remaining parameters must be keyworded IA010 5. Subroutines 8 Default parameter values
A default value is used when the actual parameter is not given. both positional and keyword parameters def compute_pay(income, exemptions = 1, tax_rate) pay = compute_pay(20000.0, tax_rate = 0.15) • once a default parameter is omitted, all remaining formal parameters must be keyworded positional parameters only • parameters with default values must be listed last float compute_pay(float income, float tax_rate, int exemptions = 1) pay = compute_pay(20000.0, 0.15); • once a default parameter is ommitted, all remaining must have default values IA010 5. Subroutines 9 Variable number of parameters
• problematic (type checking?) • can be useful (e.g. printf in C) • C – the programmer must explicitly process the parameters:
int printf(const char *format, ...); accessed using va_list (stdarg.h) • C# – variable number of parameters of the same type
public void DisplayList(params int[] list) { foreach(int next in list) { Console.WriteLine("Next value {0}", next); } }
IA010 5. Subroutines 10 Parameter-passing methods
IA010 5. Subroutines 11 Parameter-passing methods
Semantic models 1 in mode (receive data from the actual parameters) 2 out mode (transmit data to the actual parameters) 3 inout mode
Example • A subroutine takes two arrays list1 and list2, adds list1 to list2 and returns the result as revised list2. Also it returns a new array created from both arrays. • in: list1, inout: list2, out: the new list
Conceptual models • copy the value • transmit the access path (usually using a pointer or a reference) Implementation models coming next ... IA010 5. Subroutines 12 Pass-by-Value
• for in mode parameters • the value of the actual parametr initializes the corresponding formal parameter • usually implemented using copying (write-protection required if implemented using the access path) • advantages • fast for scalar values • disadvantages: • space needs to be allocated for the formal parameter • time and space needed to copy large objects (e.g. arrays)
IA010 5. Subroutines 13 Pass-by-Result
• for out mode parameters • no value is passed to the subroutine • the formal parameter acts as a normal variable • after completion, its value is copied to the actual paramter • the actual paramter must be a variable • advantages and disadvantages: • as for call-by value, plus • parameter collision • binding time choice
IA010 5. Subroutines 14 Pass-by-Result problems
Parameter collision void Fixer(out int x, out int y) { //C# x = 17; y = 35; } ... f.Fixer(out a, out a);
Binding time choice (call vs return) void DoIt(out int x, int index){ //C# x = 17; index = 42; } ... sub = 21; f.DoIt(out list[sub], out sub);
IA010 5. Subroutines 15 Pass-by-Value-Result
• for inout mode parameters • combination of the previous two • sometimes called pass-by-copy • disadvantages follow the from pass-by-value and pass-by result (time and space requirements)
IA010 5. Subroutines 16 Pass-by-Reference
• for inout mode parameters • the access path (usually an address) is transmited • the actual parameter is effectively shared with the subroutine • advantages: • very efficient (time and space) • disadvantages: • slower access (indirect addressing) • risk of unintentionally changing actual parammeters (if used for one-way communication) • can create aliases (see next slide)
IA010 5. Subroutines 17 Pass-by-Reference and aliases
• Collision between actual parameters: void foo(int &bar, int &baz) ... foo(ouch, ouch) • Collision between array elements: (for i=j) foo(list[i], list[j]) • Collision between arrays and its elements: bar(list, list[i]) • Collision between formal parameters and non-local variables: int *global; //C void main() { ... sub(global); ... } void sub(int *param) { IA010 5. Subroutines 18 ... } Pass-by-Name
• for inout mode parameters • very different from the previous models • actual parameters are textually substituted for the formal parameters • the referencing environment must also be passed to the subroutine • inefficient, hard to implement • complicated, decreases readability and reliability • Algol60, also available (but not default) in Scala • nowadays not used (exception: macros)
IA010 5. Subroutines 19 Jensen’s device
Exploits pass-by-name and side-effects. real procedure Sum(k, l, u, ak) value l, u; integer k, l, u; real ak; commentk and ak are passed by name; begin real s; s := 0; fork:=l step1 untilu do s := s + ak; Sum := s end; Pu • the code above computes k=l ak • is general: • summation over an array: Sum(i, 1, 100, V[i]) • double summation: Sum(i,l,m, Sum(j,l,n,A[i,j])) • summing squares: Sum(i,1,100,i*i)
IA010 5. Subroutines 20 Parameter passing in common PLs
• C • pass-by-value • pass-by-reference achieved using pointers • if formal parameters are pointers to constants, the actual parameters are write-protected • C++ • also contains a reference type (implicitly dereferenced) (pass-by-reference semantics) • write-protected if declared const void fun(const int &p1, int p2, int &p3) { ... } • Java • pass-by-value for all parameters • in effect pass-by-reference (objects are accessed only through references) • object reference passed as a parameter cannot be changed in the subroutine (but the referenced object can) • scalars cannot be passed by reference
IA010 5. Subroutines 21 Parameter passing in common PLs
• Ada, Fortran 95 • each parameter can be specified to be in, out, or inout • C# • pass-by-value by default • pass-by-reference can be requested using ref
void sumer(ref int oldSum, int newOne) { ... } ... sumer(ref sum, newValue);
• out parameters: passed by reference (declared out)
IA010 5. Subroutines 22 Parameter passing in Python pass-by-assignment • all data values are objects (each variable is a reference to an object) • object references are passed by value • assignment does not affect the caller def foo(x): x = x + 1
x = 42 foo(x)#x= 42 • but for mutable objects the change is visible from the outside def bar(list): list[2] = 42
list = [1,2,3] bar(list)# list= [1,2,42]
IA010 5. Subroutines 23 Type checking parameters
• big impact on program reliability • nowadays almost always enforced (exceptions: Perl, JavaScript, PHP) • historically not: Fortran 77, early C • in C89 it is possible to choose whether the parameters will be checked • two ways of defining functions double sin(x) double x; { ... } • not type checked double sin(double x) { ... } • type checked • C99 and C++ support only the second method
IA010 5. Subroutines 24 Passing multidimensional arrays
• subroutine needs to know the array dimensions for addressing (at least the number of columns) • C/C++ • separate compilation • the mapping function is( address(m[i, j]) = address(m[0,0]) + i*columns + j) • the number of columns can be given in the formal parameter:
void fun(int matrix[][10]) { .. } void main() { int mat[5][10]; ... fun(mat); ... } • alternative: pass a reference to the array + its dimensions
IA010 5. Subroutines 25 Passing multidimensional arrays 2
• Ada for unconstrained arrays we have information about index ranges:
type Mat_Type is array (Integer range <>, Integer range <>) of Float; Mat_1 : Mat_Type(1..100, 1..20);
function Sumer(Mat : in Mat_Type) return Float is Sum : Float := 0.0; begin for Row in Mat'range(1) loop for Col in Mat'range(2) loop Sum := Sum + Mat(Row, Col); end loop; -- for Col... end loop; -- for Row... return Sum; end Sumer;
IA010 5. Subroutines 26 Overloaded and generic subroutines
IA010 5. Subroutines 27 Overloaded subroutines
A subroutine is overloaded if there exists (in the same referencing environment) a different subroutine of the same name.
• overloaded subroutines must have a different protocol (number, order or types of parameters, or a different return type) • examples: C++, Java, Ada, C# • typical use case: constructors • problem 1: coercion • a call can match multiple parameter profiles • in that case there must be some order on the subroutines • complicated! (e.g. C++ [Stroustrup97]) • problem 2: default values
IA010 5. Subroutines 28 Different kinds of polymorphism
Ad hoc polymorphism • Overloaded programs. When activated, the subroutine definition is chosen which corresponds to the actual parameters. Subtype polymorphism • OOP. A variable of type T can contain an object of any subclass of T. Parametric polymorphism • a subroutine has type expressions as formal parameters • the concrete types are instantiated on activation (different activations may use different types) • a single definition, independent of type • subroutines of such kind are called generic subroutines
IA010 5. Subroutines 29 Generic functions in C++ Template functions template
• when instatied, Type is replaced by a concrete type (e.g. int or char) for which > is defined • implicit instantiation • when a function is called • when an address is obtained using &
int a, b, c; char d, e, f; ... c = max(a, b); f = max(d, e);
a copy of code is generated for each of type used IA010 5. Subroutines 30 A generic sort function
template
IA010 5. Subroutines 31 Generic functions as macros?
Let’s define the max function as a macro:
#define max(a, b) ((a) > (b)) ? (a) : (b)
• this max seems to behave as a generic function • but does not for well with side-effects: 1 take the following code:
max(x++, y)
2 code generated by the preprocessor:
((x++) > (y) ? (x++) : (y))
3 x can be incremented twice!
IA010 5. Subroutines 32 Java 5.0 generic methods public static
• simillar to Java 5.0 • no support for wildcard types • the type can be omitted (if the compiler can infer the type from the actual parameter) class MyClass { public static T Foo
IA010 5. Subroutines 34 Functions – specifics
IA010 5. Subroutines 35 Functions – specifics
• problems with side effects (if called in expressions) • aliasing problems etc. • solution (e.g. Ada): only in mode formal parameters • return value type • C: arrays and functions are not return types (pointers needed in these cases) • Ada, Python, Ruby: value of any type can be returned (Ada cannot return functions, as functions are not types) • Java and C#: methods cannot be returned (as methods are not types) • number of returned values • usually just one • Ruby: 0 (nil), 1, >1 (array) • F#: n-tuple
IA010 5. Subroutines 36 Coroutines
IA010 5. Subroutines 37 Coroutines
• the master-slave relationship does not apply • symmetric relationship among subroutines • have multiple entry points • remember their state between activations (history sensitive) • can interrupt their execution by resuming a different coroutine sub coroutine_1(){ ... resume coroutine_2(); ... resume coroutine_3(); ... } • there is only one coroutine active in any given moment • typical scenarios: • a card game • systems simulation IA010 5. Subroutines 38 Coroutines II
Example ([Sebesta])
• historically in Simula and Modula-2 • modern languages: e.g. Lua or Ruby (fibers)
IA010 5. Subroutines 39