Previous Table of Contents Next


The assumption here is that no other renaming has occurred—TEACHING_ASSISTANT takes care of the renaming to ensure replication—but that one of the two parents has redefined computer_account, for example TEACHER to express the special privileges of faculty accounts. In such a case, the rule is that one (and exactly one) of the two parent clauses in TEACHING_ASSISTANT must select the corresponding version. Note that no problem arises for an entity declared as

   ta: TEACHING_ASSISTANT

because the valid calls are of the form ta.faculty_account and ta.student_account, neither of them ambiguous (the call ta.computer_account would be invalid because after the renamings, class TEACHING_ASSISTANT has no feature of that name). The select only applies to a call

   up.computer_account

with up of type UNIVERSITY_PERSON, dynamically attached to an instance of TEACHING_ASSISTANT; then the select resolves the ambiguity by causing the call to use the version from TEACHER. For example, if we traverse a data structure of the form computer_users: LIST [UNIVERSITY_PERSON] to print some information about the computer account of each element in the list, the account used for a teaching assistant is the faculty account, not the student account. (Note that we can, if desired, redefine faculty_account in class TEACHING_ASSISTANT, using student_account, if necessary, to take into consideration the existence of another account. In all cases, we need a precise disambiguation of what computer_account means for a TEACHING_ASSISTANT object known only through a UNIVERSITY_PERSON entity.)

The select is only needed in case of replication. If the repeated inheritance rule would imply sharing, as with change_address, and one or both of the shared versions has been redeclared, the final name rule makes the class invalid because it now has two different features with the same name. (This is only a problem if both versions are effective; if one or both are deferred, there is no conflict but a mere case of feature joining as explained in section 9.9.10.) The two possible solutions follow from the previous discussions:

  If you do want sharing, one of the two versions must take precedence over the other. It suffices to undefine the other, and everything gets back to order. Alternatively, you can redefine both into a new version, which takes precedence over both.
  If you want to keep both versions, switch from sharing to replication. Rename one or both of the features so that they have different names; then you must select one of them.

9.9.14. Constrained Genericity

Eiffel’s inheritance mechanism has an important application to extending the flexibility of the genericity mechanism. In a class SOME_CONTAINER [G], as noted (section 9.7), the only operations available on entities of type G, the formal generic parameter, are those applicable to entities of all types. A generic class may, however, need to assume more about the generic parameter, as with a class SORTABLE_ARRAY [G... ], which has a procedure sort that needs, at some stage, to perform tests of the form

   if item (i) < item ( j) then ...

where item (i) and item ( j) are of type G. This requires the availability of a feature infix “<” in all types that may serve as actual generic parameters corresponding to G. Using the type SORTABLE_ARRAY [INTEGER] should be permitted because INTEGER has such a feature—but not SORTABLE_ARRAY [MATRIX] if there is no total order relation on MATRIX.

To cover such cases, declare the class as

   class SORTABLE_ARRAY [G  --> COMPARABLE] ... The rest as before ...

making it constrained generic. The symbol --> recalls the arrow of inheritance diagrams; what follows it is a type, known as the generic constraint. Such a declaration means that

  Within the class, all features of the generic constraint—here all features of COMPARABLE: infix “<”, infix “<=” and so on—may be applied to entities of type G.
  A generic derivation is only valid if the chosen actual generic parameter conforms to the constraint. Here we can use SORTABLE_ARRAY [INTEGER] because INTEGER is a descendant of COMPARABLE but not SORTABLE_ARRAY [INTEGER] if MATRIX is not a descendant of COMPARABLE.

A class can have a mix of constrained and unconstrained generic parameters, as in the EiffelBase class HASH_TABLE [G, H --> HASHABLE], whose first parameter represents the types of objects stored in a hash table, the second representing the types of the keys used to store them, which must be HASHABLE. As these examples suggest, structural property classes such as COMPARABLE, NUMERIC, and HASHABLE are the most common choice for generic constraints.

Unconstrained genericity, as in C [G], is defined as equivalent to C [G --> ANY].


Previous Table of Contents Next