160 likes | 181 Views
Subprograms. Support process abstraction and modularity characteristics of subprograms are that they have a single entry point the calling entity is suspended when control is transferred to subprogram control returns to calling entity upon termination of subprogram
E N D
Subprograms • Support process abstraction and modularity • characteristics of subprograms are that they • have a single entry point • the calling entity is suspended when control is transferred to subprogram • control returns to calling entity upon termination of subprogram • FORTRAN allows multiple entry points • Two general types of subprograms: procedures and functions • Subprogram design issues: • what mode(s) of parameter passing is used? • should parameters be type checked? • can a parameter be a subprogram name? • are local variables static or stack dynamic (or other)? • static variables do not permit recursion • is separate compilation of subprograms allowable? • can subprograms be generic or overloaded?
The subprogram header defines the type of syntactic structure (function or procedure) provides a name specifies the parameter profile the number of and types of parameters C-languages only have functions but can simulate procedures using void There are two ways that a subprogram can access data from the calling entity nonlocal (global) variables parameters Parameters in the header are formal parameters, parameters in the call are actual parameters There are many different forms of parameter passing actual parameter lists may include optional parameters available in C/C++, C#, Java, Common Lisp, Python, Ruby formal parameter lists may have initializations available in C++, FORTRAN 95, Ada, PHP, Python, Ruby most languages pass parameters by position (positional params) but some languages also allow for keyword params so that order is not important Subprogram Header and Parameters
Separate/Independent Compilation • Separate compilation allows for large software systems • for this to be available, the compiler needs access to info about data types used in the unit being compiled • separate compilation requires that subprograms be compiled in a proper order • Java, Ada, Modula-2 and FORTRAN 90 are all like this • Independent compilation allows a subprogram to be compiled without any knowledge of other subprograms • found in C, FORTRAN 77, LISP • in C, the compiler still needs to type check parameters/return types so prototypes are required • in FORTRAN 77, type checking was not performed • in LISP, there is no compile-time type checking • Pre 77 FORTRANs and Pascal are languages that allow for neither separate nor independent compilation
Static storage allows for compile-time memory allocation and deallocation ensures type checking but does not allow for recursion Stack Dynamic allows for recursion at the cost of run-time allocation/deallocation and initialization because these are stored on a stack, referencing is indirect based on stack position and possibly time-consuming, we examine this in chapter 10 Languages and their implementations: FORTRAN I-IV: static only FORTRAN 77: programmer chooses (although still no recursion) FORTRAN 90/95: static unless the subprogram is explicitly declared as recursive ALGOL 60: first to offer stack-dynamic Pascal, Modula-2, Ada, Java: only have stack-dynamic C, C++: defaults to stack dynamic, but static is allowed if declared as static in C++, variables declared in methods can only be stack-dynamic as in Java Lisp: implicit heap dynamic Local Variables
Three modes of parameter passing: in mode (params going from prog to subprog) out mode (params going from subprog to prog) inout mode (both) Implementations: Pass by Value (in) Pass by Result (out) Pass by Value-Result (inout) Pass by Reference (inout) Pass by Name (varies) Parameter Passing Methods
Pass by value: actual param used to initialize formal param but from that point forward, the formal param acts like a local variable and is entirely independent of the actual param implemented by physical data transfer (copying the value), which could be inefficient if the variable is an array or record (structure) Pass by result: the formal param acts as a local variable (uninitialized at the beginning of the subprogram) and whose value is passed by to the actual param once the subprogram terminates again, passing is done by physical data transfer Pass by value-result: combines pass by value and pass by result also referred to as pass by copy requires two copying actions, yielding the same disadvantages as with pass-by-value and pass-by-result Pass by reference: pass an access path to the variable’s stored value (a pointer) this creates an alias between the formal and actual params physical copying is limited to the address, not the datum, so this is more efficient if the param is an array or structure and nothing is passed back Implementations
This is an in-out mode implemented in ALGOL 60 but not used in many languages since in fact, because it is so confusing, it has been largely been discarded as obsolete (even dangerous) Because it is so different from the previous methods, we will take a brief look rather than passing a parameter (a value or pointer), the name of the variable is passed in the subprogram, textual substitution takes place we replace all instances of the formal param with the characters that make up the actual param We still find this approach in many languages today, but it is used in macro substitution if the language has macro expansion C has compile-time macro expansion by using #define C++ and Ada use this for generic subprograms Lisp has run-time macro substitution See the example in the notes for this slide Pass by Name
pre FORTRAN 77: pass by reference more recent FORTRAN: pass by reference for structures and pass by value-result for simple values ALGOL 60: pass by name + pass by value as an option APL and Simula 67: pass by name ALGOL 68, C, Java, C#, PHP and others: pass by value, but where pass by reference can be simulated by passing a pointer C++: same as C but with a special reference type that does not require dereferencing this allows for a true pass by reference form so that the programmer does not have to pass an explicit pointer ALGOL-W: pass by value-result Pascal, Modula 2: pass-by-value with pass-by-value-result as an option the word var in the parameter list denotes pass-by-value-result Perl: all parameters are combined into an array and the array is passed by reference Ada: 3 explicit types - in, out, in out method used is based on compiler writer’s implementation! Parameter Passing in Various Languages
Software reliability demands type checking Type checking compares formal and actual parameters for types, numbers, order, etc… usually at compile time different languages have different rules for type checking makes some languages safer than others makes some more flexible than others Language rules: F77 and earlier: no type checking at all Pascal, Modula-2, F90, Ada, Java: type checking required Original C, Perl, JavaScript, PHP: no type checking at all and checking number of parameters is also omitted in original C C++: type checking required unless you use ellipses (…) for optional parameters Parameter Type Checking
Communication between calling entity and subprogram is through the runtime stack including parameter passing by Value - copy value onto stack by Result – copy value from stack by Reference - place address of parameter on the stack and dereferencing in the subprogram by Name - implemented using “Thunks” Implementing Parameter Passing
Arrays as Parameters • As we saw in chapter 6, a mapping function must be set up by the compiler so that an array access can be mapped into a specific memory location • in languages where separate compilation of subprograms is available, the original definition of the array will have already been compiled so that the mapping function is available when compiling the subprogram • However, in languages where independent compilation is available, we need another approach • in C, C++, this is taken care of by requiring that all of the array dimensions (except for the first) is specified in the function header and function prototype • void fun(int array[ ][5][10]) • in FORTRAN, any array that is passed to a subprogram must then be declared (that is, its sizes must be described in the subprogram) • in Lisp, the mapping function can be generated at run-time, or if the arrays can change dynamically, then they are implemented as linked lists and do not use a mapping function at all
Parameters that are Subprogram names • Subprogram names might be passed as parameters • example, we want a subprogram that performs an integration estimate for area under a curve • we want the subprogram to execute independently of the function, so we write it so that the we pass function’s name that we want to integrate to an integrate subprogram • rather than writing a version of the subprogram for each function we might want to use double integrate(double *(f)(double x), double lowerbd, double upperbd) { double result, i; … result = f(i); … } This is available in C/C++, Fortran 90/95 and JavaScript
Passing Subprogram Names • Passing the subprogram’s name requires • that the subprogram’s parameters and their types be passed to the subprogram along with the subprogram’s return type • in the previous example, function f’s return type and its parameter’s type must all be specified • this provides necessary information for type checking • in C, C++, pointers to a function are passed rather than the function name itself • When passed, the correct referencing environment must be identified: • environment of the subprogram call (shallow binding) • environment of the definition of the subprogram (deep binding) • environment of the subprogram which called the subprogram passed (ad hoc binding)
Overloaded subprograms share the same name Each subprogram must have different types of parameters and/or different number of parameters at run-time, the proper subprogram is invoked based on which params are passed using overloaded subprograms is less efficient because the run-time environment must determine which set of code gets executed but it provides a programmer with the flexibility to define a given subprogram to operate on different forms of data (making the language more readable) example, a programmer writes four sort subprograms where each operates on a different type of array – array of ints, array of longs, array of floats, array of Strings the sort functions are all called using the same notation: sort(a, n); but the specific code executed depends on what type of array a is C#, C++, Java, Ada, Common Lisp have overloaded subprogs Overloaded Subprograms
Generic subprograms go beyond the overloaded subprogram by allowing the programmer to write one set of code that can operate on different types This provides a form of polymorphism in Ada, you declare a subprogram to be generic and declare the type of data as < >, you then generate specific instances of the subprogram by writing further subprogram headers which specify the types for any < > placeholders the Ada compiler then generates a version of each of these subprogram headers see the example on page 423-424 in C++, these are templates defined on classes where you specify <class name> and use name as a placeholder throughout your function unlike Ada, the compiler sets a template, not specific functions, and specific functions are generated at run-time as needed based on the type of parameter that was passed to the function Java generic methods are much like C++’s but are more flexible in that wildcard types can be specified C# is like Java except that wildcards are not allowed Dynamically bound languages (Common Lisp, APL) do not have typed variables, so all subprograms are generic Generic Subprograms
Functions are side effects allowed? not allowed in Ada what types of values can be returned? C/C++/Java/C# allow any type to be returned FORTRAN 77, Pascal, Modula-2, Ada functions allow only primitive types (no structures) User-overloaded operators available in Ada, Python, Ruby and C++ these functions are defined just like any function except that the name is an operator such as int operator * (…) to define * to be used say on vectors too much of this is not a good thing as it can harm readability Co-routines special kind of subprogram that is used to implement concurrency concurrency is covered in chapter 13 Macros most languages now have facilities for defining macros to be expanded to generate code, introduced in COBOL and extensively used in Lisp Other Topics