Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there anything composition cannot accomplish that inheritance can?

People also ask

Can you have inheritance and composition?

In most cases, composition can be used interchangeably with inheritance. One thing that makes inheritance so well-known is polymorphism. Composition is initially not designed for polymorphism. But most programming languages allow us to do that with interfaces (known as protocols in the Swift world).

Should you always use composition over inheritance?

To get the higher design flexibility, the design principle says that composition should be favored over inheritance. Inheritance should only be used when subclass 'is a' superclass. Don't use inheritance to get code reuse. If there is no 'is a' relationship, then use composition for code reuse.

Why is composition better than inheritance?

One more benefit of composition over inheritance is testing scope. Unit testing is easy in composition because we know what all methods we are using from another class. We can mock it up for testing whereas in inheritance we depend heavily on superclass and don't know what all methods of superclass will be used.

What are the disadvantages of using composition over inheritance?

The disadvantage of object composition is that the behavior of the system may be harder to understand just by looking at the source code. A system using object composition may be very dynamic in nature so it may require running the system to get a deeper understanding of how the different objects cooperate.


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

  • Delegation is inheritance

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.

  • On the notion of inheritance

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. [...]

  • Systematically refactoring inheritance to delegation in java

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. [...]


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.


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.


I may be wrong about this, but I'm going to say it anyway, and if anyone has a reason I'm wrong, please just respond with a comment and don't down-vote me. 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.