30

Composition and inheritance.

I am aware that they are both tools to be chosen when appropriate, and context is very important in choosing between composition and inheritance. However, the discussion about the appropriate context for each is usually a little fuzzy; this has me beginning to consider just how distinctly inheritance and polymorphism are separate aspects of traditional OOP.

Polymorphism allows one to specify "is-a" relationships equally as well as inheritance. Particularly, inheriting from a base class implicitly creates a polymorphic relationship between that class and its subclasses. However, whereas polymorphism can be implemented using pure interfaces, inheritance complicates the polymorphic relationship by simultaneously transferring implementation details. In this way, inheritance is quite distinct from pure polymorphism.

As a tool, inheritance serves programmers differently than polymorphism (through pure interfaces) by simplifying implementation re-use in trivial cases. In the majority of cases, however, the implementation details of a superclass subtly conflict with the requirements of a subclass. This is why we have "overrides" and "member hiding". In these cases, the implementation re-use offered by inheritance is purchased with the added effort of verifying state changes and execution paths across cascading levels of code: the complete "flattened" implementation details of the subclass are spread between multiple classes, which usually means multiple files, of which only portions apply to the subclass in question. Looking through that hierarchy is absolutely necessary when dealing with inheritance, because without looking at the code of the superclass, there is no way to know what un-overidden details are monkeying with your state or diverting your execution.

In comparison, exclusive use of composition guarantees you will see what state can be modified by explicitly instantiated objects whose methods are invoked at your discretion. Truly flattened implementation is still not achieved (and actually isn't even desirable, since the benefit of structured programming is the encapsulation and abstraction of implementation details) but you still get your code-reuse, and you will only have to look in one place when the code misbehaves.

With the goal of testing these ideas in practice, eschewing traditional inheritance for a combination of pure interface-based polymorphism and object composition, I am wondering,

Is there anything object composition and interfaces cannot accomplish that inheritance can?

Edit

In the responses so far, ewernli believes there are no technical feats available for one technique but not the other; he later mentions how different patterns and design approaches are inherent to each technique. This stands to reason. However, the suggestion leads me to refine my question by asking whether exclusive use of composition and interfaces in lieu of traditional inheritance would prohibit the use of any major design patterns? And if so, aren't there equivalent patterns for use in my situation?

David V McKay
  • 122
  • 2
  • 12
  • 3
    Personally, I like mixins. :) – Jonathan Feinberg Feb 10 '10 at 16:55
  • 1
    I don't have time to check for effective duplication, but this inheritance v. composition theme is perennially visited on SO, for ex. http://stackoverflow.com/questions/216523/object-oriented-best-practices-inheritance-v-composition-v-interfaces or http://stackoverflow.com/questions/1598722/should-i-use-inheritance-or-composition. `One can always put a twist on this theme and call it a novel take on things...` Yet one thing we should agree is that this type of question doesn't lead to definitive or even authoritative answers. Maybe a CW may be more appropriate format... – mjv Feb 10 '10 at 17:22
  • I didn't mean to rehash a tired debate. Admittedly, the way I stated my case was pretty much a one-sided sample of said debate, but my primary interest is in answering whether or not there is a use for inheritance that genuinely cannot be replaced with composition and interfaces. p.s., what is a CW format? Maybe I will try that... – David V McKay Feb 10 '10 at 17:27
  • possible duplicate of [Is Inheritance really needed?](http://stackoverflow.com/questions/278476/is-inheritance-really-needed) – nawfal Oct 03 '13 at 06:43
  • Inheritance is often used as a way to let the end-users customize certain behaviors (by overriding methods). Composition does not directly replace this aspect on inheritance, however, other techniques can, like the strategy pattern. – Scotty Jamison Mar 22 '22 at 16:43

5 Answers5

25

Technically everything that can be realized with inheritance can be realized with delegation as well. So the answer would be "no".

Transforming inheritance into delegation

Let's say we have the following classes implemented with inheritance:

public class A {
    String a = "A";
    void doSomething() { .... }
    void getDisplayName() {  return a }
    void printName { System.out.println( this.getDisplayName() };   
}

public class B extends A {
    String b = "B";
    void getDisplayName() {  return a + " " + b; }
    void doSomething() { super.doSomething() ; ... }    
}

The stuff works nicely, and calling printName on an instance of B will print "A B" in the console.

Now, if we rewrite that with delegation, we get:

public class A {
    String a = "A";
    void doSomething() { .... }
    void getDisplayName() {  return a }
    void printName { System.out.println( this.getName() };  
}

public class B  {
    String b = "B";
    A delegate = new A();
    void getDisplayName() {  return delegate.a + " " + b; }
    void doSomething() { delegate.doSomething() ; ... } 
    void printName() { delegate.printName() ; ... }
}

We need to define printName in B and also to create the delegate when B is instantiated. A call to doSomething will work in a similar way as with inheritance. But a call to printName will print "A" in the console. Indeed with delegation, we lost the powerful concept of "this" being bound to the object instance and base methods being able to call methods that have be override.

This can be solved in the language supports pure delegation. With pure delegation, "this" in the delegate will still reference the instance of B. Which means that this.getName() will starts the method dispatch from class B. We achieve the the same as with inheritance. This is the mechanism used in prototype-based language such as Self which have delegation has a built-in feature (You can read here how inheritance works in Self).

But Java doesn't have pure delegation. Are when then stuck? No really, we can still do that ourselves with some more effort:

public class A implements AInterface {
    String a = "A";
    AInterface owner; // replace "this"
    A ( AInterface o ) { owner = o }
    void doSomething() { .... }
    void getDisplayName() {  return a }
    void printName { System.out.println( owner.getName() }; 
}

public class B  implements AInterface {
    String b = "B";
    A delegate = new A( this );
    void getDisplayName() {  return delegate.a + " " + b; }
    void doSomething() { delegate.doSomething() ; ... } 
    void printName() { delegate.printName() ; ... }
}

We are basically re-implementing what the built-in inheritance provides. Does it make sense? No really. But it illustrates that inheritance can always be converted to delegation.

Discussion

Inheritance is characterized by the fact that a base class can call a method that is overridden in a sub class. This is for instance the essence of the template pattern. Such things can not be done easily with delegation. On the other hand, this is exactly what makes inheritance hard to use. It require a mental twist to understand where polymorphic dispatch happen and what is the effect if methods are overridden.

There are some known pitfalls about inheritance and the fragility it may introduce in the design. Especially if the class hierarchy evolves. There can also be some issues with equality in hashCode and equals if inheritance is used. But on the other side, it's still a very elegant way to solve some problems.

Also, even if inheritance can be replaced with delegation, one you can argue that they still achieve different purpose and complement each other -- they don't convey the same intention which is not captured by pure technical equivalence.

(My theory is that when somebody starts doing OO, we are tempted to over-use inheritance because it's perceive like a feature of the language. Then we learn delegation which is pattern/approach and we learn to like it as well. After some time, we find a balance between both and develop of sense of intuition of which one is better in which case. Well, as you can see, I still like both, and both deserve some caution before being introduced.)

Some literature

Inheritance and delegation are alternate methods for incremental definition and sharing. It has commonly been believed that delegation provides a more powerful model. This paper demonstrates that there is a “natural” model of inheritance which captures all of the properties of delegation. Independently, certain constraints on the ability of delegation to capture inheritance are demonstrated. Finally, a new framework which fully captures both delegation and inheritance is outlined, and some of the ramifications of this hybrid model are explored.

One of the most intriguing—and at the same time most problematic—notions in object-oriented programing is inheritance. Inheritance is commonly regarded as the feature that distinguishes object-oriented programming from other modern programming paradigms, but researchers rarely agree on its meaning and usage. [...]

Because of the strong coupling of classes and the proliferation of unneeded class members induced by inheritance, the suggestion to use composition and delegation instead has become commonplace. The presentation of a corresponding refactoring in the literature may lead one to believe that such a transformation is a straightforward undertaking. [...]

clickMe
  • 993
  • 11
  • 33
ewernli
  • 38,045
  • 5
  • 92
  • 123
  • Is part of this excerpted from a published paper? If so, I would be interested in a link or doi. – David V McKay Feb 10 '10 at 18:16
  • 2
    The first paragraphs are mine and is my opinion. Then there are 3 references to papers related to the subject for which I've quoted the abstract. The doi can be found in the links which all points to portal.acm.org. Sorry if that was not clear. Let me known if you can't find them as pdf. – ewernli Feb 10 '10 at 22:46
  • Thank you, I appreciate the clarification. – David V McKay Feb 11 '10 at 19:01
  • 1
    Something forced me to downvote. Even though I agree inheritance is frequently misused, the tenor of the question/answer bothers me. Inheritance is a specialized tool. Just because someone doesn't know how to use it, doesn't mean you throw it away. One could have just as easily asked: "is there any Java can do you cannot do in byte code?". Obviously not, but you highlight the issue yourself: "Does it make sense? Not really." – JoeG Sep 26 '16 at 15:31
  • I might fall in love with your answers. – Farhan stands with Palestine Sep 28 '16 at 15:34
  • your example is a good one, although not the most straightforward, just you also simply state it can overcome as if it was easy, it is not that so easy, you provided solutions of course, but are not straightforward on day to day basis, you mention hierarchy, try to do that with multi level hierarchy, where inheritance would rely on a 4th grand parent or 4th grand parent on "4th grand son" and you have extremely much of redundant and non-transparent code – FantomX1 Mar 27 '20 at 02:23
  • in inheritance automatically checks if the method exists in child call that, otherwise call the parent method, in delegation such "polymorphism"doesn't exist, of course, you can change the child (but not with parent), but you either have to explicitly define whether to call the child or the parent or have a helper method intermediator, which still calls either one, in inheritance for parent method you don't have to repeat it, only for the child extended, in delegation you have to refer it. A little questionable is, once one learns to do it routinely if inheritance is often of more advantage – FantomX1 Mar 27 '20 at 02:35
5

Composition cannot screw up life as does inheritance, when quick gun programmers try to resolve issues by adding methods and extend hierarchies (rather than give a thought to natural hierarchies)

Composition cannot result in weird diamonds, that cause maintenance teams to burn night oil scratching their heads

Inheritance was the essence of discussion in GOF Design patterns which would not have been the same if programmers used Composition in the first place.

questzen
  • 3,260
  • 18
  • 21
  • Mark me as a troll, but I did all these mistakes before learning from them – questzen Feb 10 '10 at 17:06
  • True. I have been spending the past few days fixing code fully dependent on inheritance. A necessary fix in one base class has resulted in change of 1000 lines of code. – Nitin Nanda Jan 17 '21 at 05:00
0

There is 1 situation I can think of where inheritance would be superior to composition.

Suppose I have a closed source Widget library I am using in a project (meaning the implementation details are a mystery to me besides what is documented). Now suppose each widget has the ability to add child widgets. With inheritance, I could extend the Widget class to create a CustomWidget, and then add CustomWidget as child widget of any other widget in the library. Then my code to add a CustomWidget would look something like this:

Widget baseWidget = new Widget();
CustomWidget customWidget = new CustomWidget();
baseWidget.addChildWidget(customWidget);

Very clean, and keeps in line with the library's conventions for adding child widgets. However, with composition, it would have to be something like this:

Widget baseWidget = new Widget();
CustomWidget customWidget = new CustomWidget();
customWidget.addAsChildToWidget(baseWidget);

Not as clean, and also breaks the conventions of the library

Now I'm not saying that you couldn't accomplish this with composition (in fact my example shows that you very clearly can), it's just not ideal in all circumstances, and can lead to breaking conventions and other rather visually unappealing workarounds.

miken32
  • 42,008
  • 16
  • 111
  • 154
aeskreis
  • 1,923
  • 2
  • 17
  • 24
  • 3
    You emphasized Widget was in an external, closed source library. If Widget.addChildWidget() took an argument of type Widget, then IMO inheritance is the only viable choice. The library has parents tracking children, but your composition example requires CustomWidgets to track their parents instead of being tracked by them. (Yuck!) If Widget.addChildWidget() took an argument of type IWidget, composition could still work, since CustomWidget could implement IWidget, while deferring some behaviours to a private Widget. btw, The real power of Interface Composition comes with IOC & DI. – David V McKay Mar 25 '13 at 18:01
0

Consider a gui toolkit.

An edit control is a window, it should inherit the window's close/enable/paint functions - it doesn't contain a window.

Then a rich text control should contain the edit controls save/read/cut/paste functions it would be very difficult to use if it merely contained a window and an edit control.

Martin Beckett
  • 94,801
  • 28
  • 188
  • 263
  • When discussing GUI classes, I think it is too easy to confuse visual composition with class composition. One can create IWindow declaring signatures for window-like objects, and Window to actually draw windows and handle events. Then create IEditControl and EditControl, which implement IWindow. EditControl simply delegates its IWindow responsibilities to the Window object. Publicly, EditControl looks like any other IWindow, and works like Window with EditControl embellishments. Last, RichTextControl implements IEditControl, delegating to its own EditControl object. The pattern is chainable. – David V McKay Feb 10 '10 at 18:05
  • 1
    True, most of the examples of inheritance (employee classes etc) are better done as composition. But gui toolkits really do benefit from inheritance (IMHO) – Martin Beckett Feb 10 '10 at 18:51
  • 3
    Respectfully: My company maintains a massive legacy system in .Net; By MSFT's example with WinForms, the original devs used lots of inheritance to implement UI classes. We have 18 unique (though similar) combo boxes, 12 base forms, and an inheritance hierarchy up to 8 levels deep over the CLI. Our UI framework is such a maze, so inconsistent and fragile, the current dev team is terrified of the slightest change to it. But, often, all this code falls short of new needs... Composition would've meant we could pick and choose features as needed, rather than endlessly *deriving* new combinations. – David V McKay Feb 11 '10 at 19:27
-1

Yes. It is Run Time Type Identification (RTTI).

  • If you need RTTI, frankly, you're violating DIP. But meh. Have an interface declare a `getType()` or similar function, and implement the interface. Now you have your own definition of "type", that you can mold into anything you like...and the classes involved don't need to be related to each other. – cHao Aug 08 '14 at 23:09