Hi,
Following my posts on:
It's pretty obvious I'm interested in Generalization/Specialization/Inheritance.
This thread is about discussing what and how should things be inherited when we connect two classes with the Generalization connector.
First, a few (hopefully normative) definitions. If we can't agree on the definition, then they are what we should discuss, not the consequences therefrom. Once we agree on the definitions, we can discuss the issues.
The UML 2
Superstructure Specification (abridged):
7.3.20 Generalization (from Kernel, PowerTypes)
A generalization is a taxonomic relationship between a more general classifier and a more specific classifier. Each instance of the specific classifier is also an indirect instance of the general classifier. Thus, the specific classifier inherits the features of the more general classifier.
Description:
A generalization relates a specific classifier to a more general classifier, and is owned by the specific classifier.
Semantics:
Where a generalization relates a specific classifier to a general classifier, each instance of the specific classifier is also an instance of the general classifier. Therefore, features specified for instances of the general classifier are implicitly specified for instances of the specific classifier. Any constraint applying to instances of the general classifier also applies to instances of the specific classifier.
This definition sounds good enough to me - although the impact of the definition isn't always clear (to me).
The key point about the definition is that the specialized classifier is an implicit or indirect occurrence of the generalized classifier. Thus we can correctly say (in English) the descendant inherits the characteristics of the antecedent (ancestor). Or the child inherits from the parent. The inheritance manifests itself in the availability of the current feature signature and implementation in the parent to the child.
Because of the different ways in which the different languages manage Inheritance, I'm going to use a more generic set of concepts - which I'll define as I go along.
First of all, we need to recognise that the definition provides for an inheritance hierarchy. By convention, we place the ancestors toward the "top" of the hierarchy and the descendants toward the bottom - which requires we understand that anything that is defined higher up the hierarchy is available to everything lower down the hierarchy. This is also true of multiple inheritance.
In order for a feature (defined later) to be made available to a child, it must have it's signature (to be defined later) defined in the parent. That is, we must know enough about the feature to be able to reference it in the child.
Once defined, a feature can be given effect (implemented or effected). For any given descendant, the process of making the feature available is by (upward) traversal of the hierarchy until an effected definition of the feature is found in an ancestor. That version of the feature is made available to the descendant.
A descendant may chose it's own version of the feature by one of a number of methods:
- Redefining - where the signature of the feature is changed. By implication, the feature is also reeffected.
- Reeffecting - where the signature remains the same, but the implementation is changed. If the feature has only been previously defined (usually designated abstract), this is usually known as implementing; if already implemented, this is known as overriding.
- Undefining - where the definition is no longer available (to the descendant or its children).
- Renaming - where the name is changed (for this descendant and its children)
If you are having difficulty visualising some of these concepts, EA itself can help you! If you pick a class on a diagram for which you know there are ancestors, and use Set feature visibility (Ctrl-Shift-Y) to enable ALL the actual and inherited features, then EA current does a useful (but not complete job of visualising what's currently happening to the descendant class...
You will see that EA shows you which currently available attribute or operation is provided by which ancestor. In addition, if you enable all the other compartments, you will see the same for Responsibilities, Tags and Constraints.
So, it seems to me, when we link a class to its parent by Generalization, we need to specify for each inherited feature if the descendant is going to change the version of the feature. EA does that to some extent - it asks you which operations you wish to override when you first make the connection.
What EA (and other tools) don't seem to do is to retain memory of why a particular feature exists in a class. For example, if I reeffected a feature (overrode it), and I no longer inherit the feature - because I'm now inheriting from another class or no class, shouldn't the tool at least ask the question "Do you still need this reeffected feature?" Or when you link to a new class and there is a feature with the same name in both the parent (and all ancestors) and the child, it should ask what is to be the relationship between the two?
Finally, what do we mean by Feature? Well, the UML 2
Superstructure Specification is pretty clear here:
7.3.20 Feature (from Kernel)
A feature declares a behavioral or structural characteristic of instances of classifiers.
Description:
A feature declares a behavioral or structural characteristic of instances of classifiers. Feature is an abstract metaclass.
So, it seems to me that ALL the behavioural and structural characteristics should be inheritable, this includes:
- Attributes,
- Operations,
- Constraints,
- Responsibilities,
- Parameters(in the case of Parameterized Classes)
- Arguments(in the case of classes bound to Parameterized Classes)
- Stereotypes
- The special characteristics: Persistence, IsSpeciaifcation, IsAbstract etc
- Tagged Values
- Scenarios
Well, that's what I think...
Discussion welcome.
Paolo