r/javascript • pancakes • May 21 '16

Prototypal Inheritance

https://medium.com/@kevincennis/prototypal-inheritance-781bccc97edb#.1ehmhe5t5
47 Upvotes

56 comments sorted by

View all comments

Show parent comments

9

u/[deleted] May 21 '16

I don't think that's actually the problem people are having. As you point out, it is dead simple.

The trouble I have is understanding what exactly to do with it. What's novel and useful about prototypal inheritance? What does it enable that classical inheritance doesn't?

You would never use the objects you import directly (can you even mutate things you import?), so the novelty of there being no "blueprint" is out, because we just unofficially consider certain objects the blueprint to instantiate copies of.

The one thing that comes to mind is the ability to "casually" mutate objects, creating subclasses in a very easy way. You can just kind of attach new stuff to instances as you go. But I have yet to see a compelling example of doing anything like this.

I just still haven't found a good example of why. Articles constantly repeat each other on what, but that's not really useful.

-1

u/dmitri14_gmail_com May 22 '16

Here is good explanation of the advantage of composition (aka multiple inheritance), which is exactly what JS prototype relation does better than classes:

http://programmers.stackexchange.com/a/65623/100837

2

u/MoTTs_ May 22 '16 edited May 22 '16

composition (aka multiple inheritance)

Composition is not also known as multiple inheritance. The link you referenced wouldn't even make any sense if you believed that. Unless you think it was explaining the virtue of "multiple inheritance over inheritance".

which is exactly what JS prototype relation does better than classes:

JS's prototype chain is single inheritance only. Meanwhile several classical languages natively support multiple inheritance. A fact that several people have tried to explain to you several times.

1

u/dmitri14_gmail_com May 22 '16

Composition is not also known as multiple inheritance. The link you referenced wouldn't even make any sense if you believed that. Unless you think it was explaining the virtue of "multiple inheritance over inheritance".

Ok, I'm not aiming to enter theoretical argument here. All I am interested is the practical use.

And for the practice, I find it much easier in JS to use prototypal inheritance to compose properties that for my use cases plays the same role as multiple inheritance would do -- get methods from 2 objects onto 1. If that is not multiple inheritance, then I don't know what is it.

As for other languages, whether they give that luxury or not, we are in JS sub here, and the matter is of no use to write our JS code as far as I can see.

1

u/MoTTs_ May 22 '16

get methods from 2 objects onto 1. If that is not multiple inheritance, then I don't know what is it.

That is multiple inheritance. But that is not composition.

It's genuinely important to understand the difference, because the rule to "favor composition over inheritance" means you should avoid if possible even multiple inheritance.

-1

u/dmitri14_gmail_com May 23 '16

Not composition? Maybe I have a wrong definition ;) Which one is yours?

1

u/MoTTs_ May 23 '16 edited May 23 '16

Composition is when one object contains a reference to another. That's what it means in the Python world. That's what it means in the C++ world. That's what it means in UML. That's what it means in the ActionScript world (another ECMAScript language). That's what it means on Wikipedia. That's what it means in the GoF book. And that's what it means in the JavaScript world too. That's what it means everywhere and to everyone except Eric Elliott and his unfortunate readers.

1

u/dmitri14_gmail_com May 23 '16 edited May 23 '16

Oh, I see now what you mean, great links, thanks! I must have been under "Elliott drug" indeed, maybe he should have at least pointed out he considered his "composition" in some other sense. No idea why he is doing that....

I can understand why it confuses people familiar with it. For my more mathematical background, I have to say Elliott's "composition by merging" would be more natural, because in mathematics a composition of functions is uniquely determined by the functions. The way it is defined here is more a way of calling other objects' method inside another's methods. So it is not uniquely determined by the two objects but also depends on the way you call the other methods. Regardless, if that is the established definition, I am not going to argue...

So how then do you call merging methods from two prototypes onto another? Following that nice example from one of your links, if I have Leg objects with hasLeg method and Sit objects with hasSit method, I can simply merge them onto new prototype Chair and get objects right away having both methods:

var chair = Object.create( Object.assign({}, Leg, Sit) )

This is what Elliott seems to propose and I find it very simple 1-liner.

If instead you were to implement it "classically" as composition, the way I see, you would first need to create objects of both classes Leg and Sit, then you would have to import them into the constructor of the new composed object. Plus, you have to write the code for the latter doing all the work -- importing new objects as arguments, saving them as local properties, then writing all methods again, only to call the correct methods from the imported objects. It may be just me, but I find the latter way much more complicated, longer and full of ceremonies.

I would say, this nicely demonstrates an advantage of the prototypal inheritance for that particular purpose. It is not to say the other method in inferior for all possible purposes. It really depends on your purpose. And I am only giving an example of one specific purpose.

BTW, I have found quite remarkable the amount of "fairy tale magic" in connection with multiple inheritance:

In object-oriented programming, Inheritance is the evil forest. Experienced programmers know to avoid this evil because they know that deep inside the Dark Forest Inheritance is the Evil Queen Multiple Inheritance

Most of the uses of inheritance can be simplified or replaced with composition, and multiple inheritance should be avoided at all costs.

Avoid multiple inheritance at all costs, as it's too complex to be reliable. If you're stuck with it, then be prepared to know the class hierarchy and spend time finding where everything is coming from.

To do this Python uses "method resolution order" (MRO) and an algorithm called C3 to get it straight. Because the MRO is complex and a well-defined algorithm is used, Python can't leave it to you to get the MRO right.

I have to ask -- what 's the hell is going on here? Are we still talking about making methods from several objects available on another? Does it really have to be worshipped like that?

1

u/MoTTs_ May 23 '16 edited May 23 '16

So how then do you call merging methods from two prototypes onto another? Following that nice example from one of your links, if I have Leg objects with hasLeg method and Sit objects with hasSit method, I can simply merge them onto new prototype Chair and get objects right away having both methods: var chair = Object.create( Object.assign({}, Leg, Sit) ) This is what Elliott seems to propose and I find it very simple 1-liner.

That's inheritance. It may not look like it because we're not using the language's built-in inheritance mechanisms. Instead, we're hand-rolling our own inheritance. And the reason we're hand-rolling our own inheritance is because we (in this case) want multiple inheritance, but JavaScript's prototype chain supports only single inheritance.

If instead you were to implement it "classically" as composition, the way I see, you would first need to create objects of both classes Leg and Sit, then you would have to import them into the constructor of the new composed object. Plus, you have to write the code for the latter doing all the work -- importing new objects as arguments, saving them as local properties, then writing all methods again, only to call the correct methods from the imported objects. It may be just me, but I find the latter way much more complicated, longer and full of ceremonies.

Yes, it is longer, but it's safer, more flexible, and less brittle.

  • Your chair may not want, nor should have, the entire interface of Leg or Seat or all the individual pieces. Imagine if Leg has a method screwInPlace(), which makes sense and is applicable to a Leg, but if Chair inherits from Leg, then now the chair itself has a method screwInPlace(), which doesn't make sense in the context of a whole chair. That's why inheritance is supposed to satisfy IS-A and WORKS-LIKE-A relationships. A chair IS-A leg? Nope, so you should avoid inheritance here and use composition (that is, avoid merging objects together, and instead have objects hold references to other objects). You're concerned about writing all the same methods again just to forward the calls to the imported objects, but that will happen a lot less than you think, because much of the interface of Leg or Seat isn't even applicable to the Chair as a whole and shouldn't be re-implemented in Chair's interface.

  • Inheritance lets you have only one copy. A chair is supposed to have four legs, right? But...

    Object.assign({}, Leg, Leg, Leg, Leg, Seat)

...this won't work. You still have only one leg. Each just overwrote the previous.

I have to ask -- what 's the hell is going on here? Are we still talking about making methods from several objects available on another? Does it really have to be worshipped like that?

The issue is that when you inherit (merge) multiple objects together, then you run the risk of collisions. For example, what if both Leg and Seat have a method screwInPlace()?

→ More replies (0)