Does that depend on how inheritance works in a particular language? For example, in Python it’s widely believed that inheritance is simply “a tool for code reuse” [0].
Specialization remains a very common design pattern that is incredibly useful and trivially and intuitively solved with inheritance. No other programming concept (HKT, ad hoc polymorphism, functional programming, etc...) comes close to its elegance.
Beautifully put. That matches up with my own experience learning classical OOP, even if I'm now comfortable with other models.
When someone says that "inheritance is bad for code reuse" they're not talking about interfaces, or using inheritance for polymorphism. They're strictly talking about sharing code using implementation inheritance, which is the thing that has been widely criticised for more than 30 years now.
One can argue that even the "Template Method Pattern" doesn't fall into "implementation inheritance", since the implementation lives in the subclass.
If you read the posts, discussion is way more nuanced than "inheritance bad vs inheritance good".
Here is more specifically what I meant with my comment about specialization above. There is a class with four methods, three of which are exactly what you need but the fourth one, you need to modify.
Solving this with inheritance is trivial (extend and override).
Solving this with any other paradigm is... much harder and requires a lot more boilerplate.
But anyway, creating a new method without changing any of the methods of the super class I think it's generally ok. The problems arise from modifying methods that the super class already implemented.
You may be missing the point that's being made, though. No one is arguing against interfaces, but overriding concrete methods from a concrete class. Those need to be well thought out as extension points for you to have any chance of having stable software. Not quite for free.
Somewhere deep in the code is calling a.foo(), but when you pass a subclass of A that overrides foo(), then this code "magically" calls that new implementation.
This is where specialization shines and no other paradigm allows this so elegantly and so simply.
The latter is a more general classification?
A type which inherits a default method implementation from an interface is an example of "inheritance for code reuse".
A type which inherits a method implementation from a parent class under classical OOP is also an example of "inheritance for code reuse".
However, I argue that "interface inheritance with default implementations" is superior to "classical OOP" because it avoids tight coupling with memory layout, problems with implementing multiple inheritance in classical OOP, etc.
That or abstract class/pure interface. There's no need for default implementations introducing assumptions in code.
While I take your point about introducing assumptions, I'm reluctant to give up the convenience of default implementations; they seem to present fewer problems than classically inherited methods because shallow hierarchies are more common with interfaces than with classical inheritance, and because default interface methods cannot directly access member variables because they do not know about object layout — unlike methods inherited from a parent class under classical inheritance.
https://docs.oracle.com/javase/tutorial/java/IandI/defaultme...
Having the interface implement functions does exactly that, so your point only applies for interfaces without implementations.
it's literally the same thing in practice
> including the diamond problem,
the diamond problem has only ever been a "problem" in OOP textbooks, in years and years of working on OO system I have never saw it be a problem in practice
https://www.usenix.org/legacy/publications/compsystems/1989/...
The plan seems so complex that it makes complete sense to me why languages would avoid multiple class inheritance (where each class is afforded direct access to member variables).
In contrast:
• With single inheritance, you don't have to resolve different member variable layouts because there is only one.
• With interface inheritance (with or without default methods), interface methods don't get to access struct members directly and know nothing about object memory layout.
"The diamond problem" only occurs with multiple inheritance. At a (wild-ass) guess, only a minority of "traditional" (=inheritance-based) OOP languages have that; certainly not all of them. So as far as "the diamond problem" is concerned, interfaces with default implementations are no better than single-inheritance classes.
All code reuse can be expressed with composition and delegation, bringing more flexibility, testability, cohesion, decoupling, etc, etc, etc.
Using composition or lay out data differently may yield designs with more desirable properties. There's no one answer and it depends.
To be clear, I do agree with your assertion, however I'm having a hard time actually putting "how/why" into words.
A list containing two different subclasses of your avoiding-copy-paste base class is now most likely a logical error.
So don't allow those? Supporting inheritance doesn't mean you have to support heterogeneous lists.
For example, if you call the same function from many locations those locations are now coupled since if you change the function you change all of those locations behaviour. Many times that is desirable, in which case it is good coupling. The exact same rule applies to inheritance.
The only problem with inheritance is that people can use it for classes that weren't written to be base classes, and therefore a ton of bad programmers use it for code reuse without thinking about the contract it is supposed to implement at all. With that in mind, allowing inheritance only for abstract classes isn't an issue at all.
1. Composition is often more explicit than inheritance. Inheritance is overly magic.
2. Composition avoids incidental coupling of methods. With inheritance this is unavoidable.
3. Composition is more difficult to misuse. Both composition and inheritance have their purposes. In the wild, I’ve seen inheritance misapplied much more often than I have seen with composition.