MODULE 4 Subprogram control - Subprogram sequence control, attributes of data control, Shared data in subprograms - Abstract data types revisited, Inheritance, Polymorphism. SUBPROGRAM CONTROL Subprogram control: interaction among subprograms and how subprograms manage to pass data among themselves in a structured and efficient manner. Terminology: Function call – subprograms that return values directly Subroutine call – subprograms that operate only through side effects on shared data. A.Subprogram Sequence Control Simple subprogram call return
Copy rule view of subprograms: the effect of a call statement is the same as if the subprogram were copied and inserted into the main program. Implicit assumptions present in this view : o o o o o
Subprograms cannot be recursive Explicit call statements are required Subprograms must execute completely at each call Immediate transfer of control at point of call Single execution sequence
SIMPLE CALL-RETURN SUBPROGRAMS 29
Execution of subprograms Outline of the method:
1.Subprogram definition and subprogram activation. subprogram definition:The definition is translated into a template, used to create an activation each time a subprogram is called. Subprogram activation: consists of • •
a code segment (the invariant part) - executable code and constants an activation record (the dynamic part) - local data, parameterscreated a new each time the subprogram is called,destroyed when the subprogram returns.
Execution is implemented by the use of two system-defined pointers: Current-instruction pointer – CIP-address of the next statement to be executed Current-environment pointer – CEP- pointer to the activation record.
30
On call instruction: a) b) c) d) e)
An activation record is created. Current CIP and CEP are saved in the created activation record as return point CEP is assigned the address of the activation record. CIP gets the address of the first instruction in the code segment The execution continues from the address in CIP
On return a) The old values of CIP and CEP are retrieved . b) The execution continues from the address in CIP Restrictions of the model: at most one activation of any subprogram The simplest implementation: to allocate storage for each activation as an extension of the code segment. Used in FORTRAN and COBOL. The activation record is not destroyed - only reinitialized for each subprogram execution.
Hardware support - CIP is the program counter, CEP is not used, simple jump executed on return. Stack-based implementation - the simplest run-time storage management technique
call statements : push CIP and CEP return statements : pop CIP and CEP off of the stack. Used in most C implementations LISP: uses the stack as an environment. RECURSIVE SUBPROGRAMS Specification
Syntactically - no difference Semantically - multiple activations of the same subprogram exist simultaneously at some point in the execution. Implementation
Stack-based - CIP and CEP are stored in stack, forming a dynamic chain of links. • •
A new activation record is created for each call and destroyed at return. The lifetimes of the activation records cannot overlap - they are nested. 31
Some language compilers (C, Pascal) always assume recursive structure of subprograms, while in others non-recursive subprograms are implemented in the simple way. ATTRIBUTES OF DATA CONTROL Data control features: determine the accessibility of data at different points during program execution. Central problem: the meaning of variable names, i.e. the correspondence between names and memory locations. 1.Names 1. Names and referencing environments
Two ways to make a data object available as an operand for an operation. 1.Direct transmission – A data object computed at one point as the result of an operation may be directly transmitted to another operation as an operand Example: x = y + 2*z; The result of multiplication is transmitted directly as an operand of the addition operation. Referencing through a named data object – A data object may be given a name when it is created, and the name may then be used to designate it as an operand of an operation. 1. 1. Program elements that may be named
1. Variables 2. Formal parameters 3. Subprograms 4. Defined types 5. Defined constants 6. Labels 7. Exception names 8. Primitive operations 9. Literal constants Names from 4 thru 9 - resolved at translation time. Names 1 thru 3 - discussed below. Simple names: identifiers, e.g. var1. Composite names: names for data structure components, e.g. student[4].last_name. 1. 2. Associations and Referencing Environments
32
Association: binding identifiers to particular data objects and subprograms Referencing environment: the set of identifier associations for a given subprogram. Referencing operations during program execution: determine the particular data object or subprogram associated with an identifier. Local referencing environment:
The set of associations created on entry to a subprogram that represent formal parameters, local variables, and subprograms defined only within that subprogram Nonlocal referencing environment:
The set of associations for identifiers that may be used within a subprogram but that are not created on entry to it. Can be global or predefined. Global referencing environment: associations created at the start of execution of the main program, available to be used in a subprogram, Predefined referencing environments: predefined association in the language definition. Visibility of associations
Associations are visible if they are part of the referencing environment. Otherwise associations are hidden Dynamic scope of associations
The set of subprogram activations within which the association is visible 1. 3. Aliases for data objects: Multiple names of a data object • •
separate environments - no problem in a single referencing environment - called aliases. Problems with aliasing
• •
Can make code difficult to understand for the programmer. Implementation difficulties at the optimization step - difficult to spot interdependent statements - not to reorder them
STATIC AND DYNAMIC SCOPE
The dynamic scope of an association for an identifier is that set of subprogram activations in which the association is visible during execution. Dynamic scope rules 33
relate references with associations for names during program execution.
The static scope of a declaration is that part of the program text where a use of the identifier is a reference to that particular declaration of the identifier. Static scope rules relate references with declarations of names in the program text.
Importance of static scope rules - recording information about a variable during translation. BLOCK STRUCTURE
Block-structured languages (Pascal): • •
Each program or subprogram is organized as a set of nested blocks. The chief characteristic of a block is that it introduces a new local referencing environment.
Static scope rules for block-structured program
LOCAL DATA AND LOCAL REFERENCING ENVIRONMENTS 34
Local environment of a subprogram: various identifiers declared in the subprogram variable names, parameters, subprogram names. Static scope rules: implemented by means of a table of the local declarations Dynamic scope rules: two methods: • •
Retention - associations and the bound values are retained after execution. Deletion - associations are deleted. (For further explanation and example see Figure 9.9 on p. 369)
Implementation of dynamic scope rules in local referencing environments: by means of a local environment table to associate names, types and values. Retention: the table is kept as part of the code segment Deletion: the table is kept as part of the activation record, destroyed after each execution. INHERITANCE
In the preceding lessons, you have seen inheritance mentioned several times. In the Java language, classes can be derived from other classes, thereby inheriting fields and methods from those classes. Definitions: A class that is derived from another class is called a subclass (also a derived class, extended class, or child class). The class from which the subclass is derived is called a superclass (also a base class or a parent class).
Excepting Object, which has no superclass, every class has one and only one direct superclass (single inheritance). In the absence of any other explicit superclass, every class is implicitly a subclass of Object. Classes can be derived from classes that are derived from classes that are derived from classes, and so on, and ultimately derived from the topmost class, Object. Such a class is said to be descended from all the classes in the inheritance chain stretching back to Object. The idea of inheritance is simple but powerful: When you want to create a new class and there is already a class that includes some of the code that you want, you can derive your new class from the existing class. In doing this, you can reuse the fields and methods of the existing class without having to write (and debug!) them yourself. A subclass inherits all the members (fields, methods, and nested classes) from its superclass. Constructors are not members, so they are not inherited by subclasses, but the constructor of the superclass can be invoked from the subclass. The Java Platform Class Hierarchy 35
The Object class, defined in the java.lang package, defines and implements behavior common to all classes—including the ones that you write. In the Java platform, many classes derive directly from Object, other classes derive from some of those classes, and so on, forming a hierarchy of classes.
All Classes in the Java Platform are Descendants of Object At the top of the hierarchy, Object is the most general of all classes. Classes near the bottom of the hierarchy provide more specialized behavior. An Example of Inheritance
Here is the sample code for a possible implementation of a Bicycle class that was presented in the Classes and Objects lesson: public class Bicycle { // the Bicycle class has three fields // three fields public int cadence; public int gear; public int speed; // the Bicycle class has one constructor // one constructor public Bicycle(int startCadence, int startSpeed, int startGear) { gear = startGear; cadence = startCadence; speed = startSpeed; } // the Bicycle class has 36
four methods // four methods public void setCadence(int newValue) { cadence = newValue; }
public void setGear(int newValue) { gear = newValue; } public void applyBrake(int decrement) { speed -= decrement; } public void speedUp(int increment) { speed += increment; } } A class declaration for a MountainBike class that is a subclass of Bicycle might look like this: public class MountainBike extends Bicycle { // the MountainBike subclass adds // one field one field public int seatHeight; // the MountainBike subclass has one constructor // constructor public MountainBike(int startHeight, int startCadence, int startSpeed, int startGear) { super(startCadence, startSpeed, startGear); seatHeight seatHeight = startHeight; } // the MountainBike subclass adds one method // one method public void setHeight(int newValue) { seatHeight = newValue; } } MountainBike inherits all the fields and methods of Bicycle and adds the field seatHeight and a method to set it. Except for the constructor, it is as if you had written a new MountainBike class 37
entirely from scratch, with four fields and five methods. However, you didn't have to do all the work. This would be especially valuable if the methods in the Bicycle class were complex and had taken substantial time to debug. What You Can Do in a Subclass
A subclass inherits all of the public and protected members of its parent, no matter what package the subclass is in. If the subclass is in the same package as its parent, it also inherits the package private members of the parent. You can use the inherited members as is, replace them, hide them, or supplement them with new members: • •
• • •
•
• •
The inherited fields can be used directly, just like any other fields. You can declare a field in the subclass with the same name as the one in the superclass, thus hiding it (not recommended). You can declare new fields in the subclass that are not in the superclass. The inherited methods can be used directly as they are. You can write a new instance method in the subclass that has the same signature as the one in the superclass, thus overriding it. You can write a new static method in the subclass that has the same signature as the one in the superclass, thus hiding it. You can declare new methods in the subclass that are not in the superclass. You can write a subclass constructor that invokes the constructor of the superclass, either implicitly or by using the keyword super.
The following sections in this lesson will expand on these topics. Private Members in a Superclass
A subclass does not inherit the private members of its parent class. However, if the superclass has public or protected methods for accessing its private fields, these can also be used by the subclass. A nested class has access to all the private members of its enclosing class—both fields and methods. Therefore, a public or protected nested class inherited by a subclass has indirect access to all of the private members of the superclass. Casting Objects
We have seen that an object is of the data type of the class from which it was instantiated. For example, if we write public MountainBike myBike = new MountainBike(); then myBike is of type MountainBike.
38
MountainBike is descended from Bicycle and Object. Therefore, a MountainBike is a Bicycle and is also an Object, and it can be used wherever Bicycle or Object objects are called for. The reverse is not necessarily true: a Bicycle may be a MountainBike, but it isn't necessarily. Similarly, an Object may be a Bicycle or a MountainBike, but it isn't necessarily. Casting shows the use of an object of one type in place of another type, among the objects permitted by inheritance and implementations. For example, if we write
Object obj = new MountainBike(); then obj is both an Object and a Mountainbike (until such time as obj is assigned another object that is not a Mountainbike). This is called implicit casting. If, on the other hand, we write MountainBike myBike = obj; we would get a compile-time error because obj is not known to the compiler to be a MountainBike. However, we can tell the compiler that we promise to assign a MountainBike to obj by explicit casting: MountainBike myBike = (MountainBike)obj; This cast inserts a runtime check that obj is assigned a MountainBike so that the compiler can safely assume that obj is a MountainBike. If obj is not a Mountainbike at runtime, an exception will be thrown.
Note: You can make a logical test as to the type of a particular object using the instanceof operator. This can save you from a runtime error owing to an improper cast. For example:
if (obj instanceof MountainBike) { MountainBike myBike = (MountainBike)obj; } Here the instanceof operator verifies that obj refers to a MountainBike so that we can make the cast with knowledge that there will be no runtime exception thrown.
39