I2E: Combining Genericity and Inheritance

Genericity and inheritance, the two fundamental mechanisms for generalizing classes, may be combined in two fruitful ways.

The first technique yields polymorphic data structures. Assume that in the generic class LIST [G] the insertion procedure put has a formal argument of type G, representing the element to be inserted. Then with a declaration such as pl: LIST [POLYGON]

the type rules imply that in a call pl.put (p) the permitted types for the argument p include not just POLYGON, but also RECTANGLE (an heir of POLYGON) or any other type conforming to POLYGON through inheritance.

The basic conformance requirement used here is the inheritance-based type compatibility rule: V conforms to T if V is a descendant of T.

Structures such as pl may contain objects of different types, hence the name "polymorphic data structure". Such polymorphism is, again, made safe by the type rules: by choosing an actual generic parameter ( POLYGON in the example) based higher or lower in the inheritance graph, you extend or restrict the permissible types of objects in pl. A fully general list would be declared as LIST [ANY]

where ANY, a Kernel Library class, is automatically an ancestor of any class that you may write.

The other mechanism for combining genericity and inheritance is constrained genericity. By indicating a class name after a formal generic parameter, as in VECTOR [T -> NUMERIC]

you express that only descendants of that class (here NUMERIC) may be used as the corresponding actual generic parameters. This makes it possible to use the corresponding operations. Here, for example, class VECTOR may define a routine infix "+" for adding vectors, based on the corresponding routine from NUMERIC for adding vector elements. Then by making VECTOR itself inherit from NUMERIC, you ensure that it satisfies its own generic constraint and enable the definition of types such as VECTOR [VECTOR [T]] .

As you have perhaps guessed, unconstrained genericity, as in LIST [G] , may be viewed as an abbreviation for genericity constrained by ANY, as in LIST [G -> ANY]

Something else you may have guessed: if ANY, introduced in this session, is the top of the inheritance structure -- providing all classes with universal features such as equal to compare arbitrary objects and twin to duplicate objects -- then NONE, seen earlier in the notation feature {NONE}, is its bottom. NONE indeed conceptually inherits from all other classes. NONE is, among other things, the perceived type of the Void keyword which represents a void reference.