mirror of
https://github.com/EiffelSoftware/eiffel-org.git
synced 2025-12-06 23:02:28 +01:00
Date:2008-09-19T07:54:43.000000Z git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@25 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
32 lines
3.4 KiB
Plaintext
32 lines
3.4 KiB
Plaintext
[[Property:title|12 Combining Genericity and Inheritance]]
|
|
[[Property:link_title|I2E: Combining Genericity and Inheritance]]
|
|
[[Property:weight|-3]]
|
|
[[Property:uuid|912e4c38-9add-e478-59c3-5c10aa75d784]]
|
|
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 <code> LIST [ G ] </code> the insertion procedure <code> put </code> has a formal argument of type <code> G </code>, representing the element to be inserted. Then with a declaration such as
|
|
<code>pl: LIST [POLYGON]</code>
|
|
|
|
the type rules imply that in a call <code> pl </code>. <code> put </code> <code> ( "p" ) </code> the permitted types for the argument <code> p </code> include not just <code> POLYGON </code>, but also <code> RECTANGLE </code> (an heir of <code> POLYGON </code>) or any other type conforming to <code> POLYGON </code> through inheritance.
|
|
|
|
The basic conformance requirement used here is the inheritance-based type compatibility rule: <code> V </code> conforms to <code> T </code> if <code> V </code> is a descendant of <code> T </code>.
|
|
|
|
Structures such as <code> pl </code> 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 ( <code> POLYGON </code> in the example) based higher or lower in the inheritance graph, you extend or restrict the permissible types of objects in <code> pl </code>. A fully general list would be declared as
|
|
<code>LIST [ANY]</code>
|
|
|
|
where <code> ANY </code>, 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
|
|
<code>VECTOR [T -> NUMERIC]</code>
|
|
|
|
you express that only descendants of that class (here <code> NUMERIC </code>) may be used as the corresponding actual generic parameters. This makes it possible to use the corresponding operations. Here, for example, class <code> VECTOR </code> may define a routine <code> infix </code> "+" for adding vectors, based on the corresponding routine from <code> NUMERIC </code> for adding vector elements. Then by making <code> VECTOR </code> itself inherit from <code> NUMERIC </code>, you ensure that it satisfies its own generic constraint and enable the definition of types such as <code> VECTOR </code> <code> [ </code> <code> VECTOR </code> <code> [ </code> <code> T </code> <code> ]] </code>.
|
|
|
|
As you have perhaps guessed, unconstrained genericity, as in <code> LIST </code> <code> [ G ] </code>, may be viewed as an abbreviation for genericity constrained by <code> ANY </code>, as in
|
|
<code>LIST [G -> ANY]</code>
|
|
|
|
Something else you may have guessed: if <code> ANY </code>, introduced in this session, is the top of the inheritance structure -- providing all classes with universal features such as <code> equal </code> to compare arbitrary objects and <code> clone </code> to duplicate objects -- then <code> NONE </code>, seen earlier in the notation <code> feature </code> <code> { </code> <code> NONE </code> <code> } </code>, is its bottom. <code> NONE </code> indeed conceptually inherits from all other classes. <code> NONE </code> is, among other things, the type of <code> ensure </code>, the void reference.
|
|
|
|
|
|
|
|
|