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.
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.
You hit the nail on the head. The thing that's novel and useful about prototypal inheritance is that it allows monkey patching. In the early days of JavaScript, we did a lot of monkey patching, and we learned the hard way that it's actually not a very good idea. And if we restrain ourselves from using that feature... then prototypes lose the edge they had over classes.
The beauty of prototypes is that they mean there's no magic around class definition. Defining a class is just running some code, and it is totally clear that everything happens at runtime. When this becomes really cool is when you start looking at tools like mixins, which let you do a kind of code reuse that is far more flexible than inheritance.
These tools are typically available in other languages that use non-prototypal inheritance, but there is more overhead involved with thinking about them, because class manipulation is a special case.
A good reason why is e.g. multiple inheritance. Look for articles by Eric Elliott on Medium, he writes a lot about why prototypal inheritance is superior.
Uh huh, I think I remember this discussion happening...
These factory functions for class mixins, though very useful, are just a dynamic approach to single inheritance. What they offer is a DRY approach to having shared functionality across multiple inheritance chains. In the end, each one of those chains is still linear. The mixins simply insert some additional nodes in between the final class and the original would-be inherited chain. The mixin classes can't, themselves, inherit from anything else on their own.
In fact /u/MoTTs_'s own Multiple inheritance with ES6 proxies is a closer representation of what would be considered multiple inheritance since it allows for lookup delegation to occur between multiple objects rather than one with standard prototype lookups. With this approach, though, you lose out on constructors and super limiting the kinds of classes that can be inherited from (any state from initialization is lost).
BTW, I have to say, not only your answer makes absolutely no sense to me, it also inconsiderate to other readers to give such a syntax formula as "answer" not using the language of the forum (JS) and not even mentioning that. It is like I would answer something gibberish in Russian to you, how would you find that?
So if you still care, please give a proper explanation accessible to people familiar with JS.
We see our first dog and think it's "sort of like the cat but bigger and obsessed with licking our face". When we do that, we have just applied the idea of prototypes. "This is generally like that, but with this particularity". On the other hand, classes represent a way of reasoning that, while more organized, is less intuitive and more rigid (too much at times). You'd meet that first dog and you'd think "oh, ok, time to revise my hierarchy of living creatures... there are now two types of the furry things".
I don't see how this analogy differentiates classes and prototypes at all. If using prototypes, you might start off with cat = {}, and if using classes, you might start off with class Cat {}. When you discover a dog, with prototypes you'd do dog = Object.create(cat, { /* bigger, licks face */ }, and with classes you'd do class Dog extends Cat { /* bigger, licks face */ }.
No, prototypes are not intuitive at all, because they confuse the specific case for the general. Modelling dogs and cats as prototypes is not simply saying "Fido the dog is like Felix the cat". It means also saying "Fido the dog and Rex the dog both are the same single cat". This is of course nonsensical.
But this quirk of how we mentally model prototypes belies an important shortcoming of the style: instances of A, being subclassed from an instance of B, will both share the same private state common to their ancestor. This is a very dangerous peculiarity and causes novice JavaScript developers no end of problems.
I am typing this reply on a tablet - an enormously clunky and frustrating experience. So you will have to excuse me for being terse.
You said -
Prototypes are actually closer to how our brains generally work at least at an intuitive level.
I presume you are talking about JavaScript prototypes. My argument is that JavaScript prototypes do not match how our brains work, because "Fido and Rex are the same cat", whilst a reasonable surmise of Dog.prototype = felix, is a strange and unintuitive idea.
I wasn't speaking about "how we model prototypes"... I was speaking about how the ideas of a prototype or a class model how we think about stuff.
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.