<<

IA010: Principles of Programming Languages

5.

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 ’s computation are replaced by a statement that calls the subroutine • increases readability: emphasizes logical structure, while hiding the low-level details • facilitate , 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 • 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: • • concurrent units

IA010 5. Subroutines 5 Basic definitions

• subroutine definition – describes the 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 +

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 – the programmer must explicitly 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, 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: , 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 • 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 Type max(Type first, Type second) { return first > second ? first : second; }

• 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 , 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 void generic_sort(Type list[], int len) { int top, bottom; Type temp; for (top = 0; top < len - 2; top++) for (bottom = top + 1; bottom < len - 1; bottom++) if (list[top] > list[bottom]) { temp = list[top]; list[top] = list[bottom]; list[bottom] = temp; } //** end of if(list[top]... } //** end of generic_sort use: float flt_list[100]; ... generic_sort(flt_list, 100);

IA010 5. Subroutines 31 Generic functions as macros?

Let’s define the max function as a :

#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 T foo(T[] list) { ... } ... foo(myList); differences from C++ • generic parameters must be classes (and arrays must have elements of a primitive type . . . ) • just a single instance of the code (which operates on objects of the Object class) • we can restrict the set of classes which can be used in place of the generic type public static T doIt(T[] list) { ... } wildcard types void printCollection(Collection c) { for (Object e: c) { System.out.println(e); } } IA010 5. Subroutines 33 Generic methods in C# 2005

• simillar to Java 5.0 • no support for wildcard types • the type can be omitted (if the can infer the type from the actual parameter) class MyClass { public static T Foo(T p1) { ... } } Use: int myInt = MyClass.Foo(17); // calls Foo string myStr = MyClass.Foo('apples'); // calls 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 their execution by resuming a different 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