Summary: prototypes as classes

Angus Croll anguscroll at gmail.com
Sat Jul 2 11:46:51 PDT 2011


I think its important to make a distinction between chained and unchained
prototypes...

By unchained prototypes I mean those that directly extend Object.prototype
(note that  that every built-in prototype specified by ES5 is
unchained). Unchained prototypes are gorgeous - one instance defining the
properties of many. And it's really not that hard...once you understand the
difference between Constructor.prototype and instance.__proto__ (or its
symbolic successor) you're all set. The concept itself is very simple - a
dynamic archetype to be shared by all my instances: my prototype changes, my
instances know about it. I would not want to hide such a smart, simple
concept behind the more complex and (in this scenario) less meaningful
concept of class.

By chaining prototypes together we can mimic classical inheritance: objA ->
objA.prototype -> objB.prototype -> Object.prototype. As everyone knows
prototype-chaining is non-trivial (though made easier by es5's
Object.create) and this is the rationale for a class literal in es6: let the
language absorb the complexity and let the engines make it faster.

This would be fine and good if classical inheritance were a good fit for
JavaScript, but I don't think it is:

a) The syntax may be fixable but the logic isn't. Inheritance hierarchies
are gnarly.

- Nine times out of ten it's a re-use technique masquerading as a
classification of types. Yes a shark is a fish (thanks @jb_briaud) and if
you ever need a fish and a shark in your JavaScript then classical
inheritance is for you. However if its re-use you want (and it almost always
is) then implementation inheritance is tedious at best, a death-march at
worst, because sooner or later the hierarchy becomes arbitrary and self
defeating. Single-root trees are good for representing ancestry, I can
attest that they are not good for defining re-use.

- Even when the intention is to model relationships between types the
process is awkward. Most types have multiple characteristics but classical
JavaScript allows for only one parent. Moreover classical hierarchies must
be implemented top-down - a superclass must be created before it can be
extended - yet classes closer to the root are by nature more generic and
abstract and are more easily defined *after* we have more knowledge of their
concrete classes subclasses. Hierarchy definition is by necessity iterative
which does not play well with an existing code base.

b) JavaScript already has cleaner, lightweight, more flexible options:

- Mixins allow objects to borrow from an unlimited number of other objects
regardless of lineage, while still allowing for organization of functions by
type. Mixins are way more flexible than inheritance chains - we can
buy behavior types on demand with zero impact on the larger model.
Prototypes facilitate Mixins, since a mixin is normally applied to an
unchained prototype, another reason why new developers should continue to
understand prototypes - 'class' is not a helpful concept where Mixins are
concerned.

- Delegation (call/apply) lets you grab any function whenever you need it.
Classical Inheritance is necessary when your language constrains function
usage by type hierarchy (Java, C++). JavaScript doesn't do this and doesn't
need it.

- The module pattern allows a chunk of data and functionality to
be parceled into an object which can be used anywhere without compromising
the integrity of the module's code. This ability to package up
mini-eco-systems frees the developer from constraints of context that would
occur if the same logic were defined as part of a class.

c) How does the class concept square (no pun) with objects like Math, which
is not a constructor and \therefore will not, I assume be considered a
class? Is Math.pow a const now? If so how will that work when Math is not a
class? If not that seems like an inconsistency.

tl;dr....
Unchained prototypes: Invaluable concept; would be obfuscated by class
syntax.
Chained prototypes: Class literals might fix the syntax but the not the
concept. JavaScript has better, easier tools already.

-----------

I don't buy the argument (advanced by some in this discussion group) that as
long as nothing is removed from the language, new features can't hurt.
JavaScript has fewer keywords and a more lightweight syntax than almost any
other mainstream language. For many of us that is hugely appealing and
paradoxically it makes JavaScript enormously expressive. C++ syntax has
everything but the kitchen sink (maybe that too) but as a language I suspect
it bores most of use to sobs. Less is more.

Earlier in this thread, Brendan said "I claim we can do little to control
the outcome in terms of adoption...the classical OOP patterning in many
devs' brains, count more than our exhortations." That's sad because I think
many ex-classical programmers (myself included) grew tired of implementation
inheritance as the dominant paradigm and gravitated to JavaScript (and also
functional languages) as a refuge from the stodgy tyranny of bloated
hierarchies.

The classical OOP ship may have sailed, but its taking on water. I'm not
convinced that "users don't care and they want to write new C and have it
just work" - I think that does a disservice to our community. JavaScript is
on the upward path, Java on the down. We're fostering a generation of
converts from classical OOP to something more elegant, agile and useful. It
would be a shame to throw in the towel now.

Angus

On Wed, Jun 29, 2011 at 3:08 PM, Brendan Eich <brendan at mozilla.com> wrote:

> On Jun 29, 2011, at 2:24 PM, Axel Rauschmayer wrote:
>
> >> That's all neat in a kind of desugaring ftw, nerdcore way, but tl;dr --
> users don't care and they want to write new C and have it just work (mostly;
> granted some crack the code, for a few good and bad purposes).
> >
> > Note that I am arguing from the perspective of a language that only has
> PaCs, versus a language that only has constructor functions. If you don’t,
> then we don’t disagree.
>
> That was not clear, because we keep coming back to JS as it is. That's
> where I want to land, so arguing about what-if's and might-have-been's is
> not my cup of tea.
>
>
> > You argue that constructor functions are more intuitive at the user level
> (to *all* people) and that PaCs wouldn’t “just work”
>
> I never wrote anything like either of those things, certainly not "to *all*
> people". Indeed I was the one pointing out that your universals did not
> apply to all people.
>
> Last concrete disagreement we had was over new C() vs. C() in the current
> language being notably different from new C() vs. C.constructor() in the
> alternate-reality language with prototypes as classes.
>
> /be
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20110702/5872af75/attachment.html>


More information about the es-discuss mailing list