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
the type rules imply that in a call pl . pu t (" 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
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
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
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 clone 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 type of Void , the void reference.
Eiffel Home Page (Web) -- Getting started with Eiffel (local)
Copyright Interactive Software Engineering, 2001