Object Oriented Languages Concepts 1 Lecture 14 Dolores
Object Oriented Languages Concepts: 1 Lecture 14: Dolores Zage
Mechanisms to Produce flexible and understandable software • Encapsulation • polymorphism • inheritance
OOP paradigm • Progenitor was Smalltalk • motivations – biggest - find a better module scheme for complex systems in hiding the details – smaller - find a more flexible version of assignment and then try and eliminate it altogether
Ada • six major goals – suitable for DOD embedded computer applications – appropriate for design, development, and maintenance of reliable software for large, long-lived and continually undergoing change systems – common language ( complete, unambiguous, machineindependent standards) – not impose execution costs in applications – can build a support environment around it – example of good current language design practice
Ada • In 1976, 23 existing languages were appraised • none met the six goals • 5 companies competed, Honeywell Bull of France led by Jean Ichbaih was selected • standard appeared in 1983
Major Features • • Tasks and concurrent execution real-time control of tasks exception handling abstract data types
Ada - a “new” beginning • Types in Ada • Polymorphism
Type Equivalence • What is a type? • When are types equivalent? – For example, many programming languages insist that assignments be between expressions which have “identical types” – Also, formal parameters must have the same types as the actuals in procedure and function calls • What does identical mean?
Type Equivalence • Consider the following Ada program fragment: declare type BLACK is INTEGER; type WHITE is INTEGER; B: BLACK; W: WHITE; I: INTEGER; begin W : = 5; B : = W; I : = B; end; Which of the assignments are legal?
Answer • Answers in both affirmative and negative are reasonable. • Two broad categories of type equivalence – NAME – STRUCTURAL • under name - none of the assignments are legal • under structural - all are legal
Name Equivalence Outer: declare type BLACK is INTEGER B: BLACK; INNER: declare type BLACK is FLOAT; A: BLACK; begin B : = A; end Inner; end Outer; The type A and B have the same name, namely BLACK, but the type definitions occur in different scopes. Thus their types are different even though they have same name.
Structural Equivalence Type T 1 is record Type T 2 is record Type T 3 is record Type T 4 is record X: INTEGER; N: access T 5; N: access T 1; N: access T 2; X: INTEGER; end record Type T 5 is record Y: INTEGER; N: access T 6; end record Record type T 2 just renames T 1 to T 2, under structural equivalence the name chosen for the type does not change the type, so T 1 and T 2 are structurally equivalent. Record type T 3 just substitutes names, so it too is structurally equivalent. Finally, T 4 and T 5 may or may not be equivalent. If order is not important, then T 4 is equivalent. If the field names are part of the structure (and usually they are), then T 5 is not type equivalent to the others.
Testing Equivalence • Is not easy! • C uses structural equivalence, but when this becomes difficult, i. e. , with struct, C uses name equivalence. C++ uses name equivalence. • Name equivalence is sometimes favored because it is simpler and safer
Is Name Equivalence Safer and Simpler? • Consider: – type point is record first, second: real end record; – type complex is record first, second: real end record; • These types are distinct in name equivalence, thus in the scope of – var p: point; z: complex; – both z: =p and p: =z are wrong
Is Name Equivalence Safer and Simpler? • It may be just an accident that the two types are structurally similar. The two conceptually represent completely different data structures. For this reason name equivalence is popular. • Name equivalence is not always clear, because the types of some objects do not have a user-defined or language defined name. Type T = record a: integer; b: char end; var In some versions of Pascal the types of x and y and u and v are equivalent but no others. This is called declaration equivalence x, y: array [1. . 2] of record a: integer; b: char end; z: array[1. . 2] of T; u, v: array[1. . 2] of record a: integer; b: char end;
Name Equivalence • The strict interpretation of name equivalence forces the programmer to add a few new type names, in order to ensure that certain variables have the same type. • The strict interpretation also has other considerations
Name Equivalence declare N: INTEGER; type INDEX is INTEGER range 1. . 10; I: INDEX; begin N : = I; -- illegal, different types I : = I +1; -- illegal, + is for type INTEGER not INDEX • Want an INDEX type to convey the intention that the value of the variable will be a subset of the integers, yet use it as an integer.
Types in Ada • Ada chose name equivalence • Several problems to overcome with name equivalence as we saw • Ada has two innovative type constructs (for the 80 s) – subtypes – derived types
Subtypes • Ada solution to the subrange problem is to introduce subtypes, which are not really types at all. As far as the compiler is concerned INDEX is just another name for INTEGER. The purpose of an Ada subtype is the run-time guarantee that the program will notice if the value is out of range. declare N: INTEGER; subtype INDEX is INTEGER range 1. . 10; I: INDEX; begin N : = I; -- legal I : = N; -- possible, run-time error, but type correct I : = I +1;
Subtypes • Subtypes are a way of constraining the values that variables can take at run time • The variables M and F have the same type, but assigning June to F will cause the predefined exception CONSTRAINT. ERROR to be raised. Type Month = (Jan, Feb, March, April, May, June, July, Aug, Sept, Oct, Nov, Dec); subtype Fall is month range Oct. . Dec; M : Month; F: Fall;
Derived Types • Create an isomorphic copy of another type Centimeters is new INTEGER; -- type definitions type Meters is new INTEGER; Length 1: Meters; -- variable definitions Length 2: Centimeters; Length 1 : = Length 2 -- cannot be mixed, illegal Length 1 : = 5 + 2 * Length 1; -- perfectly legal, 5 and 2 are ints
Derived Types • Functions and constants can be overloaded in Ada • Only through overload resolution can the properation be found • In overload resolution the compiler chooses from among different alternatives for the code to run for some operation. • This is DIFFERENT than conversion
Overloading • Overload resolution is particularly difficult in Ada, since the user can overload operations as well. Function “+” (cm: Centimeters, m: Meters) return Centimeters is begin return (cm + Centimeters(100 * INTEGER(m))); end “+”; Function “+” (m: Meters, cm: Centimeters) return Centimeters is begin return (cm + Centimeters(100 * INTEGER(m))); end “+”;
Overloading • Similar in C++ • but functions differing in only the return type may not have the same name • implicit coercion is not allowed in Ada int f (int i 1, int i 2) { return (8); } // f 1 int f (int i 1, double d 2) {return (3. 5); } //f 2 int x = f(1, 2); //f 1 double y = f( 1, 2. 0); //f 2 int //f 1 ( an implicit coercion to int) z = f(1. 3, 2); NOT ALLOWED
Polymorphism • An important purpose of PL design is to find the right abstractions that permit the clear expression of algorithmic ideas • also to reuse these in more complex constructions • it is tedious and error-prone to repeat the same algorithmic content with small variations • example - writing separate Pascal function for arrays of different size, or writing the C code for linked lists of one type and again for another type
Polymorphism • If a subprogram or function can assume more than one type, it is said to be polymorphic. • Polymorphism can be divided into – universal – ad hoc
Kinds of Polymorphism Universal parametric subtype Polymorphism Ad hoc overloading Implicit coercion
Ad hoc versus Universal • Distinguished by different code for the different manifestation of operators – ad hoc - the compiler chooses from an ad hoc and finite number of choices for the correct code to generate – universal - the appropriate arguments to a procedure must be a uniform collection of data structures
Overloading and Implicit Coercion • Overloading occurs when the same name is used for different functions (like the + in Ada). • Implicit coercion occurs when values of one type are routinely converted to another so that a value will have a type appropriate context.
Coercion • Consider 1/3 + 25 • in some languages the answer is 5. 333333 • one-third is computed to 15 digits of precision, 14 to the right of decimal point. Then 25 is coerced to the same, losing the most important digit the 2. • Law of least astonishment Always expect the “weirdest” outcome.
Parametric and Inclusion Polymorphism • Universal polymorphism divided into parametric and inclusion. • Differ in what facet of data structures they take advantage of • parametric takes advantage of the fact that data structures are built from many layers of constructors. Not all the layers may be relevant to a particular function.
Parametric and Inclusion Polymorphism • Inclusion takes advantage of the fact that not all fields of records may be relevant to a particular function • in both cases, the part of the data structure that is not relevant to a function is permitted to be filled by different structures with different types
Parametric • Language in which functions have type parameters as well as ordinary arguments • function id [T] (x: T) = return (x) • The identifier T is a type parameter • Notice that the type of the value argument x depends on it • id [Int] (3) • id [Real] (2. 3)
Ada Generics • A form of parametric polymorphism can be achieved in Ada using generics Generic type Type is private; function Id(X: in Type) return Type is begin return X; end;
Generic • The id Type is generic parameter - not a predefined type. • This is just a template, it is not executable • to create a function, the template must be instantiated with a particular type • function Int. Id is new Id (INTEGER); • function Float. ID is new ID(FLOAT);
Record model of OO programming • It is possible to capture the aspects of what are called OO programming languages using inclusion polymorphism • Objects are records, methods are fields with subprogram values
Ada Language Evaluation • Language was more complex than expected • took several years (late 80 s) to get an effective compiler • Ada has proven to be effective in environments where its use has been mandated, but limited in other environments • Ada is cumbersome for programming in the “small”
Ada Language Evaluation • The advent of C++ has greatly changed the Ada landscape – Ada’s use had been growing in late 80’s – the increase use of C and C++, Ada development has slowed or stopped • C++ has the advantage that the underlying implementation is visible to the programmer which allows the programmer to better understand how the program will execute • In Ada the underlying execution model is often hidden
Abstract Data Types • New data type defined by the programmer that includes – a programmer-defined data type, – a set of abstract operations on objects of that type, and – encapsulation of objects of that type in such a way that the user of the new cannot manipulate those objects by use of the predefined operations.
Data Abstraction • Fundamental part of programming • if the programming language provides little direct support for data abstraction beyond the subprogram mechanism, the programmer may still design and use his own abstract types • he uses his own “coding conventions” to organize his program so that the effect is achieved • without the support for the definition of abstract data types, encapsulation of a new type is not possible
Data Abstraction • if coding standards are violated, whether intentionally or not, the language implementation cannot detect the violation • such programmer-created abstract data types often appear as special subprogram libraries in languages such as C, FORTRAN, Pascal enforcing “protection” • Ada and C++ (Smalltalk) are among the few widely used languages with data abstraction features
Encapsulation Reviewed • Access restricted so that only subprograms that know how data objects of the type are represented are the operations defined as part of the type itself
No language support for encapsulation of abstract type definitions • Type definitions are provided by C • it is simple to declare new variables of the type, since only the type name is needed in the declaration. • Also any subprogram that can declare a variable to be of the new type is also allowed to access any component of the representation of the type • the subprogram can bypass the defined operations on the data objects and instead directly access and manipulate the components of the data objects
Language Support for encapsulation of abstract type definitions • Ada, C++ and Smalltalk provide such support • Ada through the package construct • C++ and Smalltalk through classes
Example of a Package defining an abstract data type Package Section. Type is type Student. Id is INTEGER; type Section(Max. Size: INTEGER) is private procedure Assign. Student(Sect: in out Section; Stud in Student ID); procedure Create. Section(Sect: in out Section; Instr in integer; Room in INTEGER); private type Section(Max. Size: INTEGER) is record Room: INTEGER; Instructor: INTEGER; Class. Size: INTEGER range 0. . Max. Size : =0 Class. Roll: array(1. . Max. Size) of Student. Id; end record; end; The declaration is private for type Section indicates that the internal structure of section data object is not to be accessible from subprograms outside of the package
Other observations on Package Section. Type • Each Ada package contains two parts • a specification (last slide) - defines all data, types and subprograms that are known and made visible to procedures declared in other packages • an implementation part ( the body)implementation of the procedures declared in the spec part plus addition data objects, types and procedures that are not to be made visible to other packages
Package Section. Type Body package body Section. Type is procedure Assign. Student(…) is -- statements to insert student on Class. Roll end; procedure Create. Section(…) is -- statements to initialize components of Section record end; procedure Schedule. Room(…) is -- statements to schedule section in a room end;
Other comments about Section. Type • The need of the procedure name in the package spec is clear enough - the compiler need to know the signature of the procedure if is called from another package • HOWEVER, why are the private data definitions place in the package specs, since they are information that is known and used only within the body of the package?
Implementations for abstract data types • Basically two models – indirect encapsulation – direct encapsulation
Activation record package A Activation record package B P P Indirect encapsulation of object P Direct encapsulation of object P abstract type is defined in Package A Package B declares and uses object P (abstract type in A) the actual storage for P is maintained in the activation record for package A the actual storage for P is maintained in the activation record for package B Activation record of package B must contain a pointer to the actual storage
Activation record package A Activation record package B P Difference - Indirect encapsulation of object P the implementation of the abstract data type is truly independent of its use If the structure P changes, only package A needs to change Package B only need to know that object P is a pointer and does not need knowledge of the format of the data pointed to by P For large systems with thousands of modules, time saved in not recompiling each module whenever the definition of P changes is significant Accessing P has a run-time penalty Each access of P requires an indirect pointer access to get to the actual storage. A single use is not significant, repeated access to P can be costly.
Activation record package A Activation record package B P Direct encapsulation of object P - has the opposite characteristics The data object P is stored within package B’s activation record. Accessing of P’s components may be faster, since the standard base plus offset accessing of data in a local activation record may be used; no indirection through a pointer is necessary. However, if the representation of the abstract object changes, then all instances of its use (e. g. , package B) must be recompiled. This makes system changes expensive in compilation time, but more efficient in execution.
Encapsulation Models • Ada uses the direct model, thus the need for a private section in the specification • Note, however, both direct or indirect can be used in any program that supports encapsulation, regardless of the model implemented as part of the software architecture of the programming language.
Encapsulation Models • Direct encapsulation is the favored and implied model within Ada • A clever (or unwitting) programmer can write a program such that indirect encapsulation is performed
Two encapsulation examples for Ada data package A is type My. Stack is private; procedure New. Stack(S: out My. Stack); procedure New. Stack(S: out My. Stack) private type My. Stack. Rep; type My. Stack. Rep is record -- Hidden details of My. Stack type My. Stack is access My. Stack. Rep -- B only has pointer to stack end; Top: integer; A: array(1. . 100) of integer; end record; -- B has structure of stack end; Indirect encapsulation Direct encapsulation
Inheritance • Information known in one part of the program is needed and used in another part • If you think about the actual parameters of a calling subprogram when referenced as the formal of the called subprogram, there is a concrete mechanism to do this. It is explicit. • Often we need information passed among program components implicitly -> this is inheritance
Derived Classes • Classes in languages like C++ are closely tied to the concept of encapsulation • Classes typically have a part that gets inherited by another class and a part that is used internally and hidden from outside exposure • inheritance in C++ occurs via the use of derived classes
Derived Classes in C++ Class elem { public: elem() { v=0; } void To. Elem(int b) { v =b; } int From. Elem() {return v; } private: int v; // derived class Elem. Stack continued elem pop() {size=size-1; return storage[size+1]; } private: int size; elem storage[100]; } { elem x; } Class Elem. Stack: elem { Elem. Stack y; public: int I; Elem. Stack() {size=0; } read(I); void push(elem I) x. To. Elem(I) - coercion into type elem {size=size+1; storage[size]=I; } y. push(x); …} -get integer value for I - put x on stack y
Implementing classes • Does not impose much additional work for the translator • in a derived class, only the inherited names from the base class are added to the local name space for the derived class, and only the public ones are made visible to users of that class. • Actual storage for the defined objects can be determined statically by the data definitions within the class definition • if a constructor is present, then the translator must include a call on the function whenever a new declaration is encountered (on block entry)
Implementation of Classes • Does not impose much additional work for the translator • For invocation of methods, such as x. push(I), the translation need only consider this as a call on push(x, I) viewing x as the first argument. • Storage management is the same as standard C, and the same stack-based organization. • Each instance of a class has its own data storage consisting of data objects making up objects of the class as well as pointers to all the methods defined for object of that class.
Implementation of Inheritance • Does not impose much additional work for the translator • If an object is derived from some other base class, the actual storage for the object contains all the details of its implementation. • Copy-based approach - simplest and most straightforward model to implement • delegation based approach - any object of a derived class will use the data storage of the base class. Inherited properties are not duplicated. Model requires a form of data sharing - changes in the base object may cause changes in the derived object • C++ only uses the copy-based approach
Methods • Object-Oriented ? • For many, the term has become synonymous with the concept of encapsulation • however OO means more than just combining of data and subprograms into single module. • The inheritance of methods to create new objects provides and additional power that goes beyond simple encapsulation
Virtual Function • Normal functions: each subprogram name is bound at the time of definition of the method • Virtual - dynamically bound at the time of the call of the subprogram • the delay binding allows for dynamic changes to the execution behavior of classes
Virtual Function • A function is given an attribute of virtual in its class definition, as in: • virtual void setvalue(int a, int b) • Any use of name setvalue will use the latest copy of the function setvalue if it has redefined in a derived class • if a class definition is to be used only as a base class, with all data objects being declared in a derived class, it is called an abstract class • An abstract class is a class containing a null virtual function. • virtual void setvalue( int a, int b) = 0;
C++ • Just as the development of Pascal has been associated with a single person (Niklaus Wirth), a single person is created, Bjarne Stroustrup is credited with C++. • Kept the efficiency of C, yet added the power of object inheritance
The three guiding principles • The use of classes would not result in programs executing any more slowly than programs not using classes. • In order to make sure that the addition of classes did not cause other needed features to be omitted, C programs should run as a subset of C++ programs. • No run-time inefficiency should be added to the language.
Most Principles Met • Most C programs can be compiled by a C++ compiler • Strong typing is stronger than the ‘weak’ strong typing of C. • New reserved words have been added to C++
A similar concept • Remember generics in Ada • in C++, a similar concept is called a template and may be used to define generic classes: template <class type_name> classname class_definition
Polymorphism Revisited • The use of generic in Ada allows for limited overloading of functions, where multiple instances of a function are compiled, one for each of the indicated types for the function arguments • A better implementation would avoid the generation of a new copy of each subprogram and would also avoid the complete recompilation of the entire package
C++ Language Evaluation • What is said about C carries over to C++ • language not the easiest for a novice to learn • experienced programmers, C++ permits very efficient programs to be developed • logical extension of C into OO design • greater control over data by being more strongly typed than c
C++ Language Evaluation • Provides for classes and method definitions to extend the encapsulation process of abstract data types into polymorphic functions • has advantage over language like Ada in that the underlying implementation of language features is fairly transparent, yielding programs that execute efficiently
C++ Language Evaluation • However, by limiting some of these structures to those that are efficiently executed, the language leaves it up to the programmer to develop code for complex operations. For example array bounds are constant in order to avoid the necessity of run-time descriptors for array data
Smalltalk • Smalltalk differs from the other languages in 2 important respects: • it was designed as a total system and not just as a notation for developing programs • object orientation was a primitive built-in concept, as opposed to an addition of inheritance to the existing type mechanisms in languages like C++ and Ada
Smalltalk • See Smalltalk presentation • Thanks
- Slides: 74