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.