Previous | Table of Contents | Next |
Thanks to inheritance, it is possible to write a concise class text that achieves a lot, relying on all the features inherited from direct and indirect ancestors.
This is part of the power of the object-oriented form of reuse, but can create a comprehension and documentation problem when the inheritance structures become deep: How does one understand such a class, either as client author or as maintainer? For clients, the short form, which only considers the class text, does not tell the full story about available features, and for maintainers, much of the information must be sought in proper ancestors.
These observations suggest a need for mechanisms that produce, from a class text, a version that is equivalent feature-wise and assertion-wise but has no inheritance dependency at all. This is called the flat form of the class. It is a class text that has no inheritance clause and includes all the features of the class, immediate (declared in the class itself) as well as inherited. For the inherited features, the flat form must, of course, take account of all the feature adaptation mechanisms: renaming (each feature must appear under its final name), redefinition, effecting, uneffecting, and export status change. For redeclared features, require else clauses are or-ed with the precursors preconditions, and ensure then clauses are and-ed with precursors postconditions. For invariants, all the ancestors clauses are concatenated. As a result, the flat form yields a view of the class, its features, and its assertions that conforms exactly to the view offered to clients and (except for polymorphic uses) heirs.
An Eiffel environment should provide tools to produce the flat form of a class. (In the ISE environment, users click the Flat button in the class tool to get it.)
The short form (see section 9.8.5) of the flat form of a class, known as its flat-short form, is the complete interface specification, documenting all exported features and assertionsimmediate or inheritedand hiding implementation aspects. It is the appropriate documentation for a class.
An inheritance mechanism, following from multiple inheritance, remains to be seen. Through multiple inheritance, a class can be a proper descendant of another through more than one path. This is called repeated inheritance and can be indirect, as in Figure 9.12, or even direct, when a class D lists a class A twice in its inherit clause.
FIGURE 9.12. Indirect repeated inheritance.
This particular example is in fact often used by introductory presentations of multiple inheritance, which is a grave pedagogical mistake: Simple multiple inheritance examples (such as INTEGER inheriting from NUMERIC and COMPARABLE, COMPANY_PLANE from ASSET and PLANE, and so on) should involve the combination of separate abstractions. Repeated inheritance is an advanced technique; although precious, it does not arise in elementary uses and requires a little more care.
In fact, there is only one non-trivial issue in repeated inheritance: What does a feature of the repeated ancestor, such as change_address and computer_account, mean for the repeated descendant, here TEACHING_ASSISTANT? (The sample features chosen involve a routine and an attribute; the basic rules are the same.)
There are two possibilities: sharing (the repeatedly inherited feature yields just one feature in the repeated descendant) and duplication (it yields two). Examination of various cases shows quickly that a fixed policy, or one that would apply to all the features of a class, would be inappropriate. A feature such as change_address calls for sharing: As a teaching assistant, you may be both teacher and student, but you are just one person and have just one official domicile. If there are different computers and accounts for students doing course work and for faculty, you probably have two accounts, one as a student and one as a teacher.
The Eiffel rule enables, once again, the software developer to craft the resulting class to tune it to the exact requirements. Not surprisingly, it is based on names. In accordance with the final name rule (no in-class overloading):
Repeated inheritance rule:
- A feature inherited multiply under one name is shared: It is considered to be just one feature in the repeated descendant.
- A feature inherited multiply under different names is replicated, yielding as many variants as names.
To tune the repeated descendant, feature by feature, for sharing and replication, it suffices to use renaming. If you do nothing, you obtain sharing, which is indeed in most cases the desired policy (especially for those cases of unintended repeated inheritance: making D inherit from A even though it also inherits from B, which you forgot is already a descendant of A). If you use renaming somewhere along the way, so that the final names are different, you obtain two separate features. Note that it does not matter where the renaming occurs; all that counts is whether in the common descendant, TEACHING_ASSISTANT in Figure 9.12, the names are the same or different. You can use renaming at that last stage to cause replication, but if the features have been renamed higher, you can also use last-minute renaming to avoid replication, by bringing them back to a single name.
The repeated inheritance rule gives the desired flexibility to disambiguate the meaning of repeatedly inherited features. There remains a problem in case of redeclaration and polymorphism. Assume that somewhere along the inheritance paths, one or both of two replicated versions of a feature f, such as computer_account in the example, has been redeclared. We need to define the effect of a call a.f (a.computer_account in the example) if a is of the repeated ancestor type, here UNIVERSITY_PERSON, and has become attached as a result of polymorphism to an instance of the repeated descendant, here TEACHING_ASSISTANT. If one or more of the intermediate ancestors has redefined its version of the feature, the dynamically bound call has two or more versions to choose from.
The ambiguity is resolved here through a select clause, as in
class TEACHING_ASSISTANT inherit TEACHER rename computer_account as faculty_account select faculty_account end STUDENT rename computer_account as student_account end ...
Previous | Table of Contents | Next |