2

What is the relationship corresponding to implementation inheritance (realized with private inheritance in C++) in the current UML specification (2.5.1, December 2017)?

Not to be confused with interface inheritance (subtyping) which corresponds in UML to the interface realization relationship denoted by a dashed line and hollow triangle, nor with implementation and interface inheritance (subclassing) which corresponds in UML to the generalization relationship denoted by a solid line and hollow triangle.

Note. — The book Design Patterns by Erich Gamma et al. published in 1994 (before UML) whose class diagrams are based on OMT (an ancestor of UML) used informally a solid line and hollow triangle with an “(implementation)” modifier for denoting implementation inheritance:

Class adapter

Figure. — OMT class diagram of the class Adapter design pattern.

Géry Ogam
  • 6,336
  • 4
  • 38
  • 67
  • I think that's just coding stuff and not part of UML: https://stackoverflow.com/questions/3774204/difference-between-interface-inheritance-and-implementation-inheritance – qwerty_so Dec 16 '20 at 20:37

1 Answers1

4

GoF terminology

GoF proposes some terminology (p. 13-15) which you seem to have adopted:

  • an object packages data (its state) and procedures (its methods) that are the only way to access the data (state encapsulation).
  • the interface to an object is the set of its methods’ signatures.
  • a type is the name of a particular interface.
  • a subtype is a type that is a superset of another type.
  • a supertype is a type that is a subset of another type.
  • the implementation of an object is the set of its state and methods’ implementations.
  • a class defines an object’s interface and implementation.
  • a subclass defines a class that is a superset of another class.
  • a superclass defines a class that is a subset of another class.
  • inheritance in this understanding corresponds to reusing an implementation.

This understanding is driven by reuse, the main topic of their book: types are just reuse of an interface, whereas classes are reuse of an implementation. This view is reductionist:

  • Nothing is said about the promises and expectations behind an interface (e.g. that I can only pop() from the stack if I have push()ed something on it first). It is just about the ability to accept the requests defined by the interface.
  • The distinction between an abstract class (which defines an interface without providing an implementation) and an interface is not at all clarified.

The last point is perfectly illustrated in your graphical example.

  • In the GoF narrative, Target and Adaptee are both defined as interface (see p. 141, section "participants"), whereas Adapter implements these interfaces.
  • Yet, in the schema, Target is represented as an abstract class (see p. 365) and Adapter’s Request() is implemented by calling SpecificRequest() but it is not shown that Adapter must implement SpecificRequest() as well.
  • Finally, GoF explains that Adapter is a subclass of Adaptee, which seems somewhat inconsistent.

UML perspective

The UML definition of an interface is much closer to what Liskov would call a type:

An Interface […] represents a declaration of a set of public Features and obligations that together constitute a coherent service. An Interface specifies a contract […]. The obligations associated with an Interface are in the form of constraints (such as pre- and postconditions) or protocol specifications, which may impose ordering restrictions on interactions through the Interface. Interfaces may not be instantiated. Instead, an Interface specification is implemented or realized […].

Classes define sets of features, may implement interfaces and can be instantiated.

What you call interface inheritance is ambiguous:

  • If you mean a class that implements the interface, it is interface realization, denoted by a dotted line with a hollow triangle on the side of the interface to be realized.
  • If you mean an interface that inherits another interface (subtyping), it is interface specialization, denoted by a plain line with a hollow triangle on the side of the more general interface.

What you call implementation and interface inheritance is ambiguous, since it is not clear if inheritance applies only to interface or also to implementation:

  • If you mean the implementation of an existing interface with a class, it is interface realization with a dotted line with a hollow triangle on the side of the interface to be realized.
  • If you mean the simultaneous inheritance of both an interface and their implementation, then it is class specialization, denoted by a plain line with a hollow triangle on the side of the more general class.

If with implementation inheritance you were thinking of inheriting the implementation without inheriting the interface, i.e. private inheritance, then there is nothing special foreseen in UML, and you have to translate your implementation intent into UML concepts, as explained for example in this SO question.

Now to illustrate the graphical notation, here is the class Adapter pattern as described in GoF using the participant roles:

enter image description here

And here is a more logic diagram, if considering that Adaptee is in reality an existing implementation that needs to be adapted:

enter image description here

Géry Ogam
  • 6,336
  • 4
  • 38
  • 67
Christophe
  • 68,716
  • 7
  • 72
  • 138
  • I was puzzled when reading the term _implementation inheritance_ and googled it (just to find that it seems to be used in the Java world). Looks like I'm not the only one not geting a grip on that. – qwerty_so Dec 17 '20 at 07:51
  • Thanks Chris! So the bottom line is that there is no equivalent UML relationship for private inheritance. – Géry Ogam Dec 19 '20 at 23:01
  • 1. Let me make a few remarks: 1. "inheritance in this understanding corresponds to reusing or redefining an implementation." GoF does not restrict inheritance to implementation inheritance: "It’s also important to understand the difference between class inheritance and interface inheritance (or subtyping). Class inheritance defines an object’s implementation in terms of another object’s implementation. In short, it’s a mechanism for code and representation sharing. In contrast, interface inherence (or subtyping) describes when an object can be used in place of another." (cf. p. 17). – Géry Ogam Dec 20 '20 at 01:53
  • 2. "Nothing is said about the promises and expectations behind an interface." I agree, GoF does not use Barbara Liskov’s [behavioural types](https://en.wikipedia.org/wiki/Behavioral_subtyping) (types with semantic *specifications*, such as preconditions, postconditions, invariants and the history rule). Their types are purely syntactical. – Géry Ogam Dec 20 '20 at 01:54
  • 3. "The distinction between an abstract class (which defines an interface without providing an implementation) and an interface is not at all clarified." GoF defines a class as a means to provide an object’s interface and implementation (its state and the set of its operations’ implementations). And GoF defines an abstract class as a class that cannot be instantiated. So the difference is there: an abstract class can provide an implementation, so it is not a pure interface. – Géry Ogam Dec 20 '20 at 01:54
  • 4. "In the GoF narrative, Target and Adaptee are both defined as interface (see p. 141, section "participants"), whereas Adapter implements these interfaces." Even concrete class have an interface, so GoF does not define Adaptee "as an interface" (meaning a pure interface), but as a "concrete class" (cf. p. 142) which "defines an existing interface" (cf. p. 141). – Géry Ogam Dec 20 '20 at 01:54
  • 5. "Yet, in the schema, Target is represented as an abstract class (see p. 365) and Adapter’s Request() is implemented by calling SpecificRequest() but it is not shown that Adapter must implement SpecificRequest() as well." This is exactly because Adapter should not implement SpecificRequest(). Adapter should only implement Request(), using SpecificRequest()’s implementation defined in Adaptee. – Géry Ogam Dec 20 '20 at 01:54
  • 6. "Finally, GoF explains that Adapter is a subclass of Adaptee, which seems somewhat inconsistent." I agree, it might be confusing as GoF defines a subclass as inheriting both the interface and implementation of its superclass, whereas it is not the case for Adapter which inherits only the implementation of Adaptee. – Géry Ogam Dec 20 '20 at 01:54
  • 7. "What you call interface inheritance is ambiguous:" I agree, that is an excellent remark since interface inheritance (i.e. excluding implementation inheritance) indeed maps to four different situations: interface–interface (UML specialization), interface–class (UML interface realization), class–class, and class–interface. – Géry Ogam Dec 20 '20 at 11:37
  • 8. "What you call implementation and interface inheritance is ambiguous, since it is not clear if inheritance applies only to interface or also to implementation:" I meant both interface inheritance and implementation inheritance. This maps to a single situation so this one is not ambiguous: class–class (UML specialization). – Géry Ogam Dec 20 '20 at 11:37
  • 9. "If with implementation inheritance you were thinking of inheriting the implementation without inheriting the interface, i.e. private inheritance, then there is nothing special foreseen in UML" Yes, with implementation inheritance (i.e. excluding interface inheritance) I was thinking about private inheritance. This maps to a single situation: class–class (like Adaptee and Adapter). – Géry Ogam Dec 20 '20 at 11:38
  • 10. "Now to illustrate the graphical notation, here is the class Adapter pattern as described in GoF using the participant roles:" GoF does not mean that Adaptee is a pure interface nor that this interface is inherited, they mean explicitly that Adaptee is a concrete class and that it is privately inherited (cf. p. 144), that is they mean your second class diagram. – Géry Ogam Dec 20 '20 at 11:39
  • Using a generalization relationship between `Adapter` and `Adaptee` seems indeed the closest to private inheritance, since generalization is between two classifiers at the *same level* of abstraction (e.g. `Adapter` and `Adaptee` are both concrete classes), contrary to interface realization which is between two classifiers at *different levels* of abstraction (e.g. `Adapter` is a concrete class and `Target` is an abstract class). – Géry Ogam Dec 20 '20 at 16:59
  • However the inherited members of a generalization are fully inherited by default. Are you aware of a particular UML property or UML stereotype for specifying that only the *implementations* of `Adaptee`’s operations are inherited (and not their signatures)? Thanks for the nice diagrams by the way. Which tool did you use to draw them? – Géry Ogam Dec 20 '20 at 16:59
  • @Maggyero with inheritance you don’t put anything: the operations are inherited. You can {redefine} ii if you need to. For realization, nothing is inherited, because you only say you comply with the contract. There!sno way to tell you only get the implementation (see the SO link provided in my answer). – Christophe Dec 20 '20 at 19:53
  • @Maggyero Sorry if I do not respond to your 10 points: there are some interesting thoughts and counter-thoughts. But SO isn’t meant to be a discussion forum. To summarize, my point is that GoF does not use consistently their own terminology. I am well aware of their design intents, having used them sufficiently in practice with enough variations. They could have worded the participant section in an unambiguous way, and they could have aligned graph and narrative. Anyway, the object adapter seems more interesting than the class adapter ;-) – Christophe Dec 20 '20 at 20:00