20

When should you prefer inheritance patterns over mixins in dynamic languages?

By mixins, I mean actual proper mixing in, as in inserting functions and data members into an object in runtime.

When would you use, for example, prototypal inheritance instead of mixins? To illustrate more clearly what I mean by mixin, some pseudocode:

asCircle(obj) {
  obj.radius = 0
  obj.area = function() {
    return this.radius * this.radius * 3.14
  }

myObject = {}
asCircle(myObject)
myObject.area() // -> 0
dan_waterworth
  • 7,287
  • 2
  • 34
  • 45
Magnus Wolffelt
  • 2,373
  • 2
  • 20
  • 23

4 Answers4

14

Prototypical inheritance is simple. It has a single advantage over mixins.

That is that it's a live link. if you change the prototype everything that inherits it is changed.

Example using pd

var Circle = {
  constructor: function _constructor() {
    this.radius = 0;
    return this;
  },
  area: function _area() {
    return this.radius * this.radius * Circle.PI
  },
  PI: 3.14
};

var mixedIn = pd.extend({}, Circle).constructor();
var inherited = pd.make(Circle, {}).constructor();

Circle.perimeter = perimeter;

inherited.perimeter(); // wins
mixedIn.perimeter(); // fails

function perimeter() {
  return 2 * this.radius;
}

So basically, if you want changes to the "interface" Circle to reflect at run-time to all objects that "use" it's functionality, then inherit from it.

If you do not want changes to reflect then mix it in.

Note that mixins have more purpose than that as well. Mixins are your mechanism for multiple "inheritance".

If you want an object to implement multiple "interfaces" then you will have to mix some in. The one you use for prototypical inheritance is the one you want changes to reflect for at run-time, the others will be mixed in.

Zaki
  • 133
  • 1
  • 7
Raynos
  • 8,562
  • 33
  • 47
13

My horse sense tells me this:

  • If something is useful across multiple objects or class hierarchies -- make it a mixin
  • If something is only useful along a single hierarchy -- use inheritance

Related Notes:

  • The word "useful" should be taken metaphorically
  • For those languages that don't have multiple inheritance, mixins are a good alternative
  • PHP 5.4 introduces traits that have goodness from both mixins and multiple inheritance worlds
treecoder
  • 9,475
  • 10
  • 47
  • 84
9

Use the "Is-a" test.

Inheritance is limited to the case when you can say "Subclass IS A Superclass". They are the same kind of thing. "Cheese is a Dairy Product".

Mixins are for everything else. "Cheese can be used in a sandwich". Cheese isn't a sandwich, but it participates in sandwiching.

PS. This has nothing to do with dynamic languages. Any multiple inheritance language with static compilation (i.e., C++) has the same decision point.

S.Lott
  • 45,264
  • 6
  • 90
  • 154
  • Definitely +1- static languages have mixins too. – DeadMG Dec 06 '11 at 08:08
  • Right, mixins can be done in many languages - this was not my question. Dynamic languages have certain properties which might or might not make mixins different and/or more interesting in such languages - Raynos pointed one aspect out. Furthermore, you don't point out any specific reasons why one should use the IS A concept over the mixin concept. – Magnus Wolffelt Dec 06 '11 at 09:30
  • @MagnusWolffelt: They are the same kind of thing. "Cheese is a Dairy Product". That's the rule for IS-A. What more should I say? – S.Lott Dec 06 '11 at 10:51
  • My question is more about design decisions - in what situations do you want inheritance, and for what reasons? In dynamic languages I see few reasons for picking inheritance over mixins, besides what Raynos described. Performance of object creation might be one reason. – Magnus Wolffelt Dec 06 '11 at 12:15
  • @MagnusWolffelt: "in what situations do you want inheritance" When the two classes satisfy the IS-A relationship. "Performance of object creation" is not a reason for choosing one over the other. Inheritance makes a very strong statement about the two classes of objects. Mixins makes a weaker and more flexible statement. Inheritance is used when the two classes satisfy the "IS-A" relationship. What more could I say? I can't understand your question very well. Can you clarify what more you'd like to know? – S.Lott Dec 06 '11 at 12:28
  • For what actual reasons do you choose one over the other? Does the more flexible mixin strategy, in your opinion, have significant drawbacks in dynamic languages? – Magnus Wolffelt Dec 06 '11 at 12:32
  • @MagnusWolffelt: "For what actual reasons do you choose one over the other?" When the two classes satisfy the IS-A relationship. Again. There's not much more to say. Is the concept of "is-a" confusing? Is that why you keep asking the same question again and again? Also. What part of "This has nothing to do with dynamic languages" is confusing to you? Can you provide some hint as to why my answer is so confusing? – S.Lott Dec 06 '11 at 13:09
  • @S.Lott the problem that's confusing is in javascript in particular there is very little difference in putting properties on a "class" by prototypically inheriting from another object or putting properties on a "class" by extending that object with a bag of properties. So from an outside point of view, these two techniques look very similar. – Raynos Dec 06 '11 at 14:06
  • @Raynos: Yes. Javascript is confusing. However. The title of the question and the question body say "dynamic languages". If the question is **exclusively** about Javascript, the title and the question should be changed to say "in Javascript only" and exclude all other dynamic languages in which this is not confusing. – S.Lott Dec 06 '11 at 14:18
  • In that case I made a broad assumption about dynamic languages. Is it not possible to create a new class by extending another class through mixins rather then inheriting it in say python/ruby ? – Raynos Dec 06 '11 at 14:23
  • @Raynos: Python has multiple inheritance. You can subclass a single parent class or multiple (mixin) parent classes. You can easily create a "diamond" of inheritance which is resolved through Python's Method Resolution Order (MRO) rules. It's important to reserve inheritance for "is-a" and use delegation (or mixin) for everything else. – S.Lott Dec 06 '11 at 14:27
  • @S.Lott, why do you use inheritance at all if, seemingly, it has no clear advantages over using mixins for everything? Why is it 'important to reserve inheritance for "is-a"'? – Magnus Wolffelt Dec 06 '11 at 16:41
  • @MagnusWolffelt: One word: Polymorphism. "Is-a" Means that the two things have the same interface -- they're polymorphic distinct implementations of the same interface. – S.Lott Dec 06 '11 at 17:01
  • I still don't really follow... what makes polymorphism of two implementations different from having two different mixins that you choose from, mixing in the same interface but with differing internal behaviour? – Magnus Wolffelt Dec 07 '11 at 13:25
  • @MagnusWolffelt: Clarity. It's simply a question of clarity. IS-A and inheritance are not **required**. They're available so that you can clearly state a relationship. Class definitions are not **required**. You can write everything as flat collection of static methods in a single class definition and avoid all the ways that OO programming makes things clearer. Nothing is **required**. But inheritance can make things **Clear**. Programming is supposed to be about **meaning**. Hence inheritance to formalize and clarify the **meaning**. – S.Lott Dec 07 '11 at 16:26
  • Ok, fair enough :) – Magnus Wolffelt Dec 08 '11 at 12:13
0

Well, the best example I can give it to you is an Actor for a game which has inheritance for some base stuff but uses mixins/plugins for shared functionality. The shared functionality could be (directly from the source code!):

var plugins = {
    SingleVisualEntity : SingleVisualEntity,
    JumpBehaviour      : JumpBehaviour,
    WeaponBehaviour    : WeaponBehaviour,
    RadarBehaviour     : RadarBehaviour,
    EnergyGatherer     : EnergyGatherer,
    LifeBarPlugin      : LifeBarPlugin,
    SelectionPlugin    : SelectionPlugin,
    UpgradePlugin      : UpgradePlugin,
    BrainPlugin        : BrainPlugin,
    PlanetObjectPlugin : PlanetObjectPlugin,
}
Totty.js
  • 170
  • 7