Java – Why are inheritance and polymorphism so widely used

cjavaobject-orientedpythontype-systems

The more I learn about different programming paradigms, such as functional programming, the more I begin to question the wisdom of OOP concepts like inheritance and polymorphism. I first learned about inheritance and polymorphism in school, and at the time polymorphism seemed like a wonderful way to write generic code that allowed for easy extensibility.

But in the face of duck typing (both dynamic and static) and functional features such as higher-order functions, I've begun to look at inheritance and polymorphism as imposing an unnecessary restriction based on a fragile set of relationships between objects. The general idea behind polymorphism is that you write a function once, and later you can add new functionality to your program without changing the original function – all you need to do is create another derived class which implements the necessary methods.

But this is a lot simpler to achieve through duck typing, whether it's in a dynamic language like Python, or a static language like C++.

As an example, consider the following Python function, followed by its static C++ equivalent:

def foo(obj):
   obj.doSomething()

template <class Obj>
void foo(Obj& obj)
{
   obj.doSomething();
}

The OOP equivalent would be something like the following Java code:

public void foo(DoSomethingable obj)
{
  obj.doSomething();
}

The major difference, of course, is that the Java version requires the creation of an interface or an inheritance hierarchy before it will work. The Java version thus involves more work, and is less flexible. Additionally, I find that most real-world inheritance hierarchies are somewhat unstable. We've all seen the contrived examples of Shapes and Animals, but in the real world, as business requirements change and new features are added, it's difficult to get any work done before you need to really stretch the "is-a" relationship between sub-classes, or else remodel/refactor your hierarchy to include further base-classes or interfaces in order to accommodate new requirements. With duck typing, you don't need to worry about modeling anything – you just worry about the functionality you need.

Yet, inheritance and polymorphism are so popular that I doubt it would be much of an exaggeration to call them the dominant strategy for extensibility and code reuse. So why are inheritance and polymorphism so wildly successful? Am I overlooking some serious advantages that inheritance/polymorphism have over duck typing?

Best Answer

I mostly agree with you, but for fun I'll play Devil's Advocate. Explicit interfaces give a single place to look for an explicitly, formally specified contract, telling you what a type is supposed to do. This can be important when you're not the only developer on a project.

Furthermore, these explicit interfaces can be implemented more efficiently than duck typing. A virtual function call has barely more overhead than a normal function call, except that it can't be inlined. Duck typing has substantial overhead. C++-style structural typing (using templates) can generate huge amounts of object file bloat (since each instantiation is independent at the object file level) and doesn't work when you need polymorphism at runtime, not compile time.

Bottom line: I agree that Java-style inheritance and polymorphism can be a PITA and alternatives should be used more often, but it still has its advantages.