Wednesday, December 3, 2014

Diamonds are not an Object's Best Friend

Once again, I turn to a post I made on reddit for inspiration.

Some people wonder why inheritance branch but never join.  Why not tie two different families of objects together and extend both of 'em?

I can see the point of that, one could conceivably build objects that join several disparate branches of inheritance into large and versatile classes.  Conceivably.  One could also get oneself into a world of trouble, though, and this is most easily explained via the so-called diamond inheritance problem.

Please note that you cannot do this and expect your code to compile, it's just a conceptual demonstration.
Diamond.java
public class Diamond extends Class1, Class2 {
}

Class1.java
public class Class1 {
    public void doSomething() {
         System.out.println("Class1.doSomething()");
    }
}

Class2.java
public class Class2 {
    public void doSomething() {
         System.out.println("Class2.doSomething()");
    }
}
Now you have a main that uses the above classes:
public static void main(String[] args) {
    Diamond diamond = new Diamond();
    diamond.doSomething();
}
So, when you run main, what happens? This is the essence of the diamond problem. You wind up having two lines of inheritance converging on one and run into a quite serious issue.

This basically just scratches the surface of the problem, of course.  We can also think about what happens when you try to invoke something in super.  The question would have to become 'which super'?  There are many potential negative ramifications from the interactions that could be created by allowing this kind of inheritance, and the creators of Java decided that the best way to avoid them was by preventing the issue altogether.
One can achieve most of the positive effects of multiple inheritance via Interfaces and a few helpful design patterns such as Adapter, Composite and Decorator.