Inheritance is evil

(written by lawrence krubner, however indented passages are often quotes). You can contact lawrence at: lawrence@krubner.com, or follow me on Twitter.

Interesting:

All of the pain caused by inheritance can be traced back to the fact that inheritance forces ‘is-a’ rather than ‘has-a’ relationships. If class R2Unit extends Droid, then a R2Unit is-a Droid. If class Jedi contains an instance variable of type Lightsabre, then a Jedi has-a Lightsabre.

The other kind of inheritance

By the way, my gripe is with concrete inheritance – one class deriving from another and inheriting behavior from the parent class. I have no problem with interface inheritance, where only method signatures are inherited.

The difference between is-a and has-a relationships is well known and a fundamental part of OOAD, but what is less well known is that almost every is-a relationship would be better off re-articulated as a has-a relationship.

Eh?

Instead of extending a class and adding some functionality in the subclass, try putting the new functionality into its own class. Suppose you want to create a DarkJedi class; a dark Jedi is like a standard Jedi, but with dark powers too. The obvious way to do this is by extending the Jedi class and adding some appropriate methods:

// bad
class Jedi {
function drawSabre():Sabre { … }
}
class DarkJedi extends Jedi {

function crushTownspeople():void { … }
}
dj:DarkJedi = new DarkJedi();
dj.crushTownspeople();
This looks like the simplest approach, and it is at first. However, your dark powers are locked up inside the DarkJedi class. If you need to make a DarkDroid and a DarkSpaceship that can both also crush townspeople, you’re in trouble. These classes obviously can’t extend Jedi, so you have to duplicate townspeople crushing functionality across your whole DarkArmy or split it out into utility functions that you call from every crushTownspeople method. Either way, it gets complicated.

Now suppose you had done it like this:

// good
class Jedi {
function drawSabre():Sabre { … }
}
class DarkPowers {
function crushTownspeople():void { … }
}
class DarkJedi extends Jedi {
// DarkJedi has-a DarkPowers
public var darkPowers:DarkPowers = new DarkPowers();
}
dj:DarkJedi = new DarkJedi();
dj.darkPowers.crushTownspeople();
Everything that was possible in the first version is still possible in the second, but because DarkPowers is a separate class, there’s no limit on what kind of object can be evil:

class DarkHippo {
public var darkPowers:DarkPowers = new DarkPowers();
public function capsizeCanoe(canoe:Canoe):void { … }
}
Yeah, but I don’t make Jedis. Or hippos.

Good point, but the problem above happens everywhere that inheritance does. I’ll give an example from the Flash player API because I consider Actionscript 3.0 is one of the most beautiful works of software engineering I have used in recent years, and if the team that made it can’t get inheritance to behave properly, how can the rest of us be expected to?

Post external references

  1. 1
    http://berniesumption.com/software/inheritance-is-evil-and-must-be-destroyed/
Source