460 likes | 633 Views
TL: Subroutines. Programming Fundamentals 14 Feliks Klu ź niak. There are two kinds of subroutines in TL: procedures and functions . There are two kinds of subroutines in TL: procedures and functions . Procedures are invoked in procedure call statements , e.g.,
E N D
TL: Subroutines Programming Fundamentals 14 Feliks Kluźniak TL: Subroutines
There are two kinds of subroutines in TL: procedures and functions. TL: Subroutines
There are two kinds of subroutines in TL: procedures and functions. Procedures are invoked in procedure call statements, e.g., write_string( stdout, “Hello!” ); do_it() these are arguments TL: Subroutines
There are two kinds of subroutines in TL: procedures and functions. Procedures are invoked in procedure call statements, e.g., write_string( stdout, “Hello!” ); do_it() A very useful predefined procedure is called assert. It takes one boolean argument: if the argument is false, you will get an error message and the program will halt. Example: assert( 0 =< i and i < size( a ) ) TL: Subroutines
There are two kinds of subroutines in TL: procedures and functions. Procedures are invoked in procedure call statements, e.g., write_string( stdout, “Hello!” ); do_it() A very useful predefined procedure is called assert. It takes one boolean argument: if the argument is false, you will get an error message and the program will halt. Example: assert( 0 =< i and i < size( a ) ) Do sprinkle your programs liberally with such assertions: when some of them fail, you will be glad you did! TL: Subroutines
There are two kinds of subroutines in TL: procedures and functions. Procedures are invoked in procedure call statements, e.g., write_string( stdout, “Hello!” ); do_it() Functions are invoked within expressions, e.g., high_bit := power( 2, word_size – 1 ); euler_ok := exp( i * pi() ) + 1 = 0 TL: Subroutines
There are two kinds of subroutines in TL: procedures and functions. Procedures are invoked in procedure call statements, e.g., write_string( stdout, “Hello!” ); do_it() Functions are invoked within expressions, e.g., high_bit := power( 2, word_size – 1 ); euler_ok := exp( i * pi() ) – 1 = 0 Notice that we must use parentheses even when there are no arguments. This distinguishes a subroutine invocation from an occurrence of the name of a variable. TL: Subroutines
Declaring a procedure: procname(arg1,arg2, … ) begin imports of global variables and constants local declarations statements end TL: Subroutines
Declaring a procedure: procname(arg1,arg2, … ) begin imports of global variables and constants local declarations statements end The body of a procedure is similar to the body of a program, and forms a new scope. Body of the procedure TL: Subroutines
Declaring a procedure: • procname(arg1,arg2, … ) • begin • imports of global variables and constants • local declarations • statements • end • The body of a procedure is similar to the body of a program, and forms a new scope. • Local declarations are not “visible” outside the body. Body of the procedure TL: Subroutines
Declaring a procedure: • procname(arg1,arg2, … ) • begin • imports of global variables and constants • local declarations • statements • end • The body of a procedure is similar to the body of a program, and forms a new scope. • Local declarations are not “visible” outside the body. • Global variables and constants (but not subroutines or types) must • be explicitly imported. Body of the procedure TL: Subroutines
Declaring a procedure: • procname(arg1,arg2, … ) • begin • imports of global variables and constants • local declarations • statements • end • The body of a procedure is similar to the body of a program, and forms a new scope. • Local declarations are not “visible” outside the body. • Global variables and constants (but not subroutines or types) must • be explicitly imported. • The names from the list of arguments are also visible in (and local to) this scope. Body of the procedure TL: Subroutines
Declaring a procedure: procname(arg1,arg2, … ) begin … end This is the list of formal arguments. The list may be empty (but the parentheses must be there.) TL: Subroutines
Declaring a procedure: procname(arg1,arg2, … ) begin … end This is the list of formal arguments. The list may be empty (but the parentheses must be there.) When the procedure is invoked, the names of the formal arguments will represent the actual arguments in the invocation (i.e., the procedure call statement). The details must be explained … TL: Subroutines
Declaring a procedure: procname(arg1,arg2, … ) begin … end The simplest declaration of a formal argument has the following form: nameOfArgument:NameOfType Such an argument is said to be passed by value. It represents a memory location that is filled by a copy of the value of the actual argument. TL: Subroutines
Declaring a procedure: procname(arg1,arg2, … ) begin … end The simplest declaration of a formal argument has the following form: nameOfArgument:NameOfType Such an argument is said to be passed by value. It represents a memory location that is filled by a copy of the value of the actual argument. The actual argument may be an arbitrary expression of the type named in the declaration. TL: Subroutines
Declaring a procedure: procname(arg1,arg2, … ) begin … end The simplest declaration of a formal argument has the following form: nameOfArgument:NameOfType Such an argument is said to be passed by value. It represents a memory location that is filled by a copy of the value of the actual argument. The actual argument may be an arbitrary expression of the type named in the declaration. NOTE: In TL, the type of an argument passed by value must fit in one machine word (i.e., it must be a basic type or a pointer type). So it cannot be an array type, for example.
Declaring a procedure: Example: procPrintChar ( c : char ) begin globalvarstdout; write( stdout, c ) end TL: Subroutines
Declaring a procedure: Example: procPrintChar ( c : char ) begin globalvarstdout; write( stdout, c ) end This can be invoked, e.g., by PrintChar( chr( ord( ‘0’ ) + 5 ) ) During execution of the statement in PrintChar, the name c will represent … What? TL: Subroutines
Declaring a procedure: procname(arg1,arg2, … ) begin … end A formal argument can also be declared like this: refnameOfArgument:NameOfType Such an argument is said to be passed by reference. It represents a memory location that is filled by the address of the actual argument. TL: Subroutines
Declaring a procedure: procname(arg1,arg2, … ) begin … end A formal argument can also be declared like this: refnameOfArgument:NameOfType Such an argument is said to be passed by reference. It represents a memory location that is filled by the address of the actual argument. The actual argument must be a variable of the type named in the declaration. TL: Subroutines
Declaring a procedure: procname(arg1,arg2, … ) begin … end A formal argument can also be declared like this: refnameOfArgument:NameOfType Such an argument is said to be passed by reference. It represents a memory location that is filled by the address of the actual argument. The actual argument must be a variable of the type named in the declaration. An element of an array variable, such as a[ i ] , is also a variable. TL: Subroutines
Declaring a procedure: Example: proc Swap ( ref a : int, ref b : int ) begin a , b := b , a end This can be invoked, e.g., by Swap( alpha, beta ) but not by Swap( 3, alpha + 1 ) TL: Subroutines
Declaring a procedure: Example: proc Swap ( ref a : int, ref b : int ) begin a , b := b , a end This can be invoked, e.g., by Swap( alpha, beta ) but not by Swap( 3, alpha + 1 ) What will be the result of Swap( alpha, beta ) ? TL: Subroutines
Declaring a procedure: • Example: • procSwapV ( a : int, b : int ) • begin • a , b := b , a • end • In this procedure the arguments are passed by value. • What will be the result of SwapV( alpha, beta ) ? TL: Subroutines
Declaring a procedure: • Example: • procSwapV ( a : int, b : int ) • begin • a , b := b , a • end • In this procedure the arguments are passed by value. • What will be the result of SwapV( alpha, beta ) ? • Note that in Swap() the assignment a, b := b, a is compiled to code that is very different from the code to which it is compiled in SwapV() . TL: Subroutines
procSwapV ( a : int, b : int ) begin a , b := b , a end The value of b is 2. The value of a is 1. Store the value 2 in a. Store the value 1 in b. So the values of a and b are swapped, but alpha and beta don’t change. proc Swap( ref a : int, ref b : int ) begin a , b := b , a end 1. The value of the variable whose address is in b is 2. 2. The value of the variable whose address is in a is 1. 3. Store the value 2 in the variable whose address is in a. 4. Store the value 1 in the variable whose address is in b. So the values of alpha and beta are swapped. a: 1 b: 2 a: 101 b: 220 (alpha) 101: 1 (beta) 220: 2 (alpha) 101: 1 (beta) 220: 2 TL: Subroutines
Declaring a procedure: procname(arg1,arg2, … ) begin … end Finally, the third form of declaring an argument: ref constnameOfArgument:NameOfType Such an argument is said to be passed by constant reference. It represents a memory location that is filled by the address of the actual argument. The actual argument must be a variable of the type named in the declaration. However, the procedure cannot modify such an argument! TL: Subroutines
Declaring a procedure: procname(arg1,arg2, … ) begin … end Finally, the third form of declaring an argument: ref constnameOfArgument:NameOfType Such an argument is said to be passed by constant reference. It represents a memory location that is filled by the address of the actual argument. The actual argument must be a variable of the type named in the declaration. However, the procedure cannot modify such an argument! This is mostly used to pass arguments that are to be treated as constants, but that cannot be passed by value (e.g., arrays). TL: Subroutines
Declaring a procedure: Example: procSwapC ( refconst a : int, refconst b : int ) begin a , b := b , a end The compiler will detect an error! TL: Subroutines
Declaring a procedure: The problem of aliasing: When an argument is passed by reference, we may run into the problem of having the same variable represented by different names. Consider: proc Assign ( ref a : int, ref const b : int ) begin a := a + 1; a := b end We expect a call like Assign( v, w ) to assign the value of w to v, i.e., to be equivalent to v := w . Indeed, it will be so. TL: Subroutines
Declaring a procedure: The problem of aliasing: When an argument is passed by reference, we may run into the problem of having the same variable represented by different names. Consider: proc Assign ( ref a : int, ref const b : int ) begin a := a + 1; a := b end We expect a call like Assign( v, w ) to assign the value of w to v, i.e., to be equivalent to v := w . Indeed, it will be so. However, the effect of Assign( v, v ) will be quite different from that of v := v . Why? TL: Subroutines
Declaring a procedure: The problem of aliasing: A similar problem arises when a procedure imports a global variable: proc P ( ref a : int ) begin globalvar v; a := v + 1; v := v + 1 end Here we expect the global variable v to be incremented, and the argument to be assigned this new value of v. TL: Subroutines
Declaring a procedure: The problem of aliasing: A similar problem arises when a procedure imports a global variable: proc P ( ref a : int ) begin globalvar v; a := v + 1; v := v + 1 end Here we expect the global variable v to be incremented, and the argument to be assigned this new value of v. But the effect of P( v ) will be … What? TL: Subroutines
Declaring a procedure: • Good advice: • Be aware of the pitfalls. • Avoid importing global variables if you can. • If you must import, import it as a constant, if you can. • Do not pass arguments by non-constant reference, unless it is the • explicit purpose of the procedure to modify them. TL: Subroutines
Declaring a function: funcname(arg1,arg2, … ) :type of value begin imports of global variables and constants local declarations statements return expression end Since a function call will appear in an expression, the function must return a value . The type of that value must be declared, and the function must end with an expression that is to be its value. TL: Subroutines
Declaring a function: Example: func square ( a : int ) : int begin return a * a end This can be invoked, for example, by v := square( square( w + 1 ) ) % the fourth power of (w + 1) TL: Subroutines
Declaring a function: Example: func square ( a : int ) : int begin return a * a end This can be invoked, for example, by v := square( square( w + 1 ) ) % the fourth power of (w + 1) Please note that there is no recursion here. What happens is this: the value of w + 1 is computed and passed to square(); TL: Subroutines
Declaring a function: Example: func square ( a : int ) : int begin return a * a end This can be invoked, for example, by v := square( square( w + 1 ) ) % the fourth power of (w + 1) Please note that there is no recursion here. What happens is this: the value of w + 1 is computed and passed to square(); square() returns its value; TL: Subroutines
Declaring a function: Example: func square ( a : int ) : int begin return a * a end This can be invoked, for example, by v := square( square( w + 1 ) ) % the fourth power of (w + 1) Please note that there is no recursion here. What happens is this: the value of w + 1 is computed and passed to square(); square() returns its value; that value is passed to a new invocation of square() . TL: Subroutines
Declaring a function: • Example: • func square ( a : int ) : int • begin • return a * a • end • This can be invoked, for example, by • v := square( square( w + 1 ) ) % the fourth power of (w + 1) • Please note that there is no recursion here. What happens is this: • the value of w + 1 is computed and passed to square(); • square() returns its value; • that value is passed to a new invocation of square() . • A widely-used convention is that when we refer to a procedure or a function, we add empty parentheses to its name (even if argument list would not be empty in an invocation). TL: Subroutines
Declaring a function: In TL a function cannot have side effects. This means that it cannot make assignments to global variables, and cannot invoke procedures. TL: Subroutines
Declaring a function: • In TL a function cannot have side effects. • This means that it cannot make assignments to global variables, and cannot invoke procedures. • For convenience, there are some exceptions to this rule: • You are allowed to use assert() . • You are allowed to use TRACE • (but these, remember, should be removed from the • final version of your program) TL: Subroutines
Declaring a function: In TL a function cannot have side effects. This means that it cannot make assignments to global variables, and cannot invoke procedures. So the arguments of a function must be passed either by value or by constant reference… TL: Subroutines
Declaring a function: In TL a function cannot have side effects. This means that it cannot make assignments to global variables, and cannot invoke procedures. So the arguments of a function must be passed either by value or by constant reference… and a function can import variables only as constants: global const variable_name, … TL: Subroutines
Declaring a function: Example: % Sum of the elements of an integer array. % func Sum ( refconst a : ArrayOfInteger ) : int begin var sum : int; “sum” is not “Sum” var k : int; k := 0; sum := 0; while k != size( a ) do sum := sum + a[ k ]; k := k + 1 od; return sum end TL: Subroutines