I've always liked the idea of having multiple inheritance supported in a language. Most often though it's intentionally forgone, and the supposed "replacement" is interfaces. Interfaces simply do not cover all the same ground multiple inheritance does, and this restriction can occasionally lead to more boilerplate code.
The only basic reason I have ever heard for this is the diamond problem with base classes. I just can't accept that. To me, it comes off an awful lot like, "Well, it's possible to screw it up, so it's automatically a bad idea." You can screw up anything in a programming language though, and I mean anything. I just cannot take this seriously, at least not without a more thorough explanation.
Just being aware of this problem is 90% of the battle. Furthermore I think I heard something years ago about a general-purpose work-around involving an "envelope" algorithm or something like that (does this ring a bell, anyone?).
Concerning the diamond problem, the only potentially genuine problem I can think of is if you're trying to use a third-party library and can't see that two seemingly unrelated classes in that library have a common base class, but in addition to documentation, a simple language feature could, let's say, require that you specifically declare your intent to create a diamond before it'll actually compile one for you. With such a feature, any creation of a diamond is either intentional, reckless, or because one is unaware of this pitfall.
So that all being said...Is there any real reason most people hate multiple inheritance, or is it all just a bunch of hysteria that causes more harm than good? Is there something that I am not seeing here? Thank you.
Example
Car extends WheeledVehicle, KIASpectra extends Car and Electronic, KIASpectra contains Radio. Why doesn't KIASpectra contain Electronic?
Because it is an Electronic. Inheritance vs. composition should always be an is-a relationship vs. a has-a relationship.
Because it is an Electronic. There are wires, circuit boards, switches, etc. all up and down that thing.
Because it is an Electronic. If your battery goes dead in the winter, you're in just as much trouble as if all your wheels suddenly went missing.
Why not use interfaces? Take #3, for instance. I don't want to write this over and over again, and I really don't want to create some bizarre proxy helper class to do this either:
private void runOrDont()
{
if (this.battery)
{
if (this.battery.working && this.switchedOn)
{
this.run();
return;
}
}
this.dontRun();
}
(We're not getting into whether that implementation is good or bad.) You can imagine how there may be several of these functions associated with Electronic that are not related to anything in WheeledVehicle, and vice-versa.
I wasn't sure whether to settle down on that example or not, since there is room for interpretation there. You could also think in terms of Plane extending Vehicle and FlyingObject and Bird extending Animal and FlyingObject, or in terms of a much purer example.
Traits
- they act like interfaces with optional implementation, but have some restrictions that help prevent issues like the diamond problem from arising.KiaSpectra
isn't anElectronic
; it has Electronics, and may be anElectronicCar
(which would extendCar
...)