Inheritance is evil, and must be destroyed

When I built Animator.js, I got some flack for suggesting that inheritance is not a Good Thing. Keen to avoid a holy war I restated my position to ‘inheritance is often useful, but more often overused.’ Over the last few months I’ve been trying to figure out exactly when it should be used, and have concluded – at least for the kind of systems GUI developers build – never.

I’ve been working on a Flash port of Animator.js that’s been pumped up on performance enhancing drugs and given a flame thrower. It’s a fairly complex software component with around 30 classes, but it uses the Strategy Pattern instead of inheritance. I’ve grown fairly passionate about my anti-inheritance stand, and want to take some time to explain myself. In this article I rant for a few paragraphs in an attempt to persuade you not to use inheritance, and then show you how to use for Strategy Pattern for your own software.

The code samples for this article are in Actionscript but the concept applies just as much to JavaScript, or indeed any object oriented language.

Why inheritance sucks

Skip this and go straight to the code, if you like

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 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?

Here are 2 examples of use of inheritance, one appropriate and one not, and by ‘appropriate’ I mean that the problems that inheritance inevitably ends up causing are probably outweighed by the lower complexity.

Good

In Flash the DisplayObject hierarchy is a set of classes that represent the different kinds of on-screen object:

The DisplayObject hierarchy is a good use of inheritance. MovieClip extends Sprite and adds a timeline. A MovieClip is-a Sprite through and through: the fundamental defining purpose of a MovieClip is to be ‘a new kind of Sprite’. A MovieClip can always be used in place of a Sprite, it has the same methods and the same capabilities as a sprite, it is drawn on-screen like a Sprite; it just adds some extra timeline functionality on top.

More importantly, you generally don’t need to use the timeline features in the MovieClip class independently of the on-screen drawing features of the Sprite class.

It’s not all perfect. Last week I wanted to add some common functionality to both MovieClips and Sprites, but I couldn’t because it’s not possible to modify the DisplayObjectContainer base class that both these classes extend (and I refuse to monkey patch). In the end I had to use MovieClips where Sprites would do, which is inefficient.

It would be possible to re-articulate this relationship as has-a: the functionality in the MovieClip class would be split into a Timeline class, and MovieClip would extend Sprite with a public ‘timeline’ property.

// old style:
mc.goToAndPlay("shizzle");
// would become:
mc.timeline.goToAndPlay("shizzle");

But the existing version works well enough, and I think that the Flash API architect(s) made the right decision.

Bad

In flash, code to dispatch DOM events is contained in the EventDispatcher class.

EventDispatcher is a bad use of inheritance because in order to dispatch events, classes extend EventDispatcher. This is an incorrect analysis: just because a class can dispatch events, it does mean that fundamental defining purpose of the class is to be ‘a new kind of EventDispatcher’. Chances are that the class has a different fundamental purpose and the ability to dispatch events is secondary to the main purpose of the object.

This is fine for DisplayObjects, because all DisplayObjects dispatch events, and DisplayObject extends EventDispatcher, but what do you do if you want to dispatch events from an object that cannot extend EventDispatcher because it is already extending something else, perhaps Array for example? In this case, you must jump through hoops with the IEventDispatcher interface and a lot of extra boilerplate code.

This problem would not occur if instead of extending EventDispatcher in order to dispatch events, a class had a public property ‘events’ that contained an EventDispatcher. Instead of calling foo.addEventListener(), you would call foo.events.addListener(). This could either be a convention, or could be enforced with an interface. Now any class can participate in the event system just by adding a public property, because the relationship has been re-articulated from ‘x is an EventDispatcher’ to ‘x has an event dispatcher’.

(In all fairness to the Flash player API team, they made this decision because they were following the DOM Events specification, which requires that methods like addEventListener exist on the DOM nodes themselves, not as a separate events object)

Enough already, show me the code!

An example

Suppose you have a Ball class that implements a red Ball. You extend this class to make a BouncingBall class that, well, bounces. You again extend Ball to make a FadingBall class that fades in and out. Don’t ask me why, let’s just assume your client is strange. It might look something like this (the ball, not the client):

class Ball extends MovieClip {    
    function Ball() {
        graphics.beginFill(0xAA0000);
        graphics.drawCircle(0, 0, 20);
        graphics.endFill();
    }
}
class BouncingBall extends Ball {
    private var frame:int = 0;
    function BouncingBall() {
        addEventListener(Event.ENTER_FRAME, setPosition);
    }
    private function setPosition(e:Event):void {
        frame++;
        this.y = 280 - Math.abs(Math.cos(frame / 15) * 200);
    }
}
class FadingBall extends Ball {
    private var frame:int = 0;
    function FadingBall() {
        addEventListener(Event.ENTER_FRAME, setAlpha);
    }
    private function setAlpha(e:Event):void {
        frame++;
        this.alpha = Math.abs(Math.cos(frame / 15));
    }
}

Now suppose you want to make a ball that bounces and fades. Feck. Your problem here is that bouncing and fading balls aren’t really new kinds of ball, they’re new ways that the same ball behaves. The ball has-a bouncing behavior. Using inheritance, the code that handles bouncing and fading is locked up in the BouncingBall and FadingBall classes and can’t be used elsewhere.

If you’re paying any attention you know the solution by now:

// To create a bouncing and fading ball:
// var d = new StrategyBall();
// d.yMotionStrategy = new AbsSineStrategy(80, 200);
// d.alphaStrategy = new AbsSineStrategy(0, 1);
class StrategyBall extends MovieClip {
 
    public var yMotionStrategy:NumberSequenceStrategy;
    public var alphaStrategy:NumberSequenceStrategy;
 
    function StrategyBall() {
        graphics.beginFill(0xAA0000);
        graphics.drawCircle(0, 0, 20);
        graphics.endFill();
        addEventListener(Event.ENTER_FRAME, handleEnterFrame);
    }
 
    private function handleEnterFrame(e:Event):void {
        if (yMotionStrategy != null) {
            y = yMotionStrategy.nextValue();
        }
        if (alphaStrategy != null) {
            alpha = alphaStrategy.nextValue();
        }
    }
}
interface NumberSequenceStrategy {
    function nextValue():Number;
}
// Note how one class is used for both the fading and bouncing behavior - componentisation allows
// for greater code reuse
class AbsSineStrategy implements NumberSequenceStrategy {
 
    private var frame:int = 0;
    private var from:Number;
    private var to:Number;
 
    public function AbsSineStrategy(from:Number, to:Number) {
        this.from = from;
        this.to = to;
    }
 
    public function nextValue():Number {
        frame++;
        return to + Math.abs(Math.sin(frame / 15)) * (from - to);
    }
}

Apart from being able to make a bouncing, fading ball, there are 2 huge benefits of this solution:

  1. You can change the behaviour of each ball at runtime: a bouncing ball can become a fading ball at any time.
  2. You can reuse number generation algorithms between properties – note how there is only one number generation algorithm – AbsSineStrategy – is parametrised with the too and from values so that it can be use to control alpha or height.

That’s enough theory – in my next Article I’ll actually do something useful with all this stuff!

Recommended article

A fascinating and detailed account of the move from concrete inheritance to composition in game programming.

101 Responses to Inheritance is evil, and must be destroyed

  1. NoQuarter says:

    ———————————————————————-
    To: thpigdog
    ———————————————————————-
    Now say we have a rule “all dogs chase cats”.
    dog.See(cat) implies dog.Chase(cat)

    This could be written as a method,

    void Dog.See(Cat cat)
    {
    Chase(cat);
    }

    Now suppose we have a class CatLovingDog that inherits from Dog.

    void CatLovingDog.See(Cat cat)
    {
    Greet(cat);
    }
    ———————————————————————-

    No, rather than creating “some other kind of dog”, (the same fundamental inheritance problem discussed in the article), instead the thing to do is to modify the existing dog definition by adding a “CatAffinity” property.

    void Dog.See(Cat cat)
    {
    if (this.CatAffinity > 0)
    Greet(cat);
    else
    Chase(cat);
    }

    Chase or greet is not an “is-a”, nor is it a “has-a”. Instead it’s an attribute of a specific instance.

  2. Nick says:

    C++ multiple inheritance works great! The classic diamond problem is solved by the compiler mentioning the ambiguity of your code. I have bent over backwards trying to find a work around to not having multiple inheritance in C# (or same thing with Java, AS3). The best I can do is create an interface of the second class I want to derive from and, eeeeeeeeewwwwww, copy and paste the implementations of its methods. Such a shame. I blame Java for this. Correct me if im wrong but they are the bastards that started the whole interface thing.

  3. anonymous says:

    Pink at the top of the page template is eye bleeding (#ff0080). The bottom color of the gradient (#b3002d) goes nice with the textured grey.

    • bernie says:

      I disagree. #FF0080 (DEEP PINK, FUCHSIA) is the greatest of all the colours. Your eyes only bleed if they aren’t awesome enough to handle all that pink!

  4. felis leo says:

    Google GWT has an hybrid approch :

    interface IsXxx {
    Xxx asXxx();
    }

    Yes, you have to copy/paste the Xxx field declaration and this declared getter, but that’s all.
    You are free to respect this IsXxx contract by either inheritance or aggregation.
    (Even you are no more concerned by method name collision)

    Meanwhile, C++ multi-inheritance provides two facilities:
    – you don not have to { cast as Xxx / use xxx field / use asXxx getter }
    – child classes have access to parent’s protected members

    Actually i think the mostly used of inherintance is to simplify a composition.
    By exemple, if to make a X you need a common B and custom C
    with inheritence: X/B are base, C extends X/B
    with agregation: X is interface, B and C classes, C’ assemble B and C to become a X
    and you need extra interfaces to define communication between B and C, and the rest of the world…

    Finally I agree: inheritence is bad, but a shortcut.

  5. charly brown says:

    dont know if some1 pointed it before, but this topic is a “inheritance versus composition” dilema.

    Inheritance isnt evil neither is composition, they just are tools/techniques and you have to use them wisely in your design. (thats why you have to think about your design instead of start writting code and doing iterations in a backstracking (test and error way)

    “is-a”: inheritance
    “has-a”: composition

    lets imagine this 2 classes:
    public abstract class Horse extends BaseLifeForm.
    public abstract class Truck extends BaseMachine.

    this is making an asumption: machines will never be a life form, so you have 2 hierarchies: lifeforms and machines. ¿but what if some day artificial intelligence makes possible that machines became a form of life? UPS!
    anyways: horses will never have a “turn on” method…. ¿or not?

    at the end, its all about making a design based in some scenario.

    disclaimer: english is not my native language so dont blame my mistakes :)

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>