Summary: prototypes as classes

Angus Croll anguscroll at gmail.com
Sat Jul 2 16:10:38 PDT 2011


Good to know you share some concerns (esp. with respect to class side
inheritance, too many options, and classical OOP as a dominant methodology).

>>The difference is just induction from 1 to 2 (assuming you don't extend
Object.prototype, which ES5 allows you to do now without breaking for-in
loops -- from 2 to 3 if you do extend Object.prototype).
Is a difference in degree really a difference in kind or meaning? I don't
think so

I'd argue its a difference in meaning - the proof is that if you removed
'extends' and 'super', the class sugar would support unchained prototypes
only. In fact maybe I could live with 'class' alone (though it might give
noobs the wrong idea about JavaScript vs Java) - but it's 'extends' and
'super' which add legitimacy to the classical OOP approach.

>>Some empirical results: "...Studies of C++ programs mention a maximum DIT
of 8 and a median of 1, whereas Smalltalk has a median of 3, and maximum of
10. Figure 6 shows that in all but four sites, the median prototype chain
length is 1

Sure, proto chaining was always supported but my guess is that officially
sanctioning 'extends' and 'super' will raise the median prototype chain
length through the roof - and I can't see how that's good for the language

>>Mixins require copying properties, and there's nothing lightweight (in
usable syntax or runtime cost) in that.

As an aside I'm not wild about the mixin by copying strategy and have
advocated mixin by delegation as an alternative.
http://javascriptweblog.wordpress.com/2011/05/31/a-fresh-look-at-javascript-mixins/


>>I think you are protesting too much.

Yeah you might be right. I hope so. And I'm probably biased because Java
taught me to abhor impl. inheritance  On the other hand I held back from
writing to this list for the longest time until I was certain I had a
serious concern. You made a great language, I'd be sad to see it misused
because folks were drawn to the wrong kind of sugar - I know there are a
bunch of others who don't write to this list but share my concern.

Angus





On Sat, Jul 2, 2011 at 2:04 PM, Brendan Eich <brendan at mozilla.com> wrote:

> Remember, I'm the one who is a little sad about classes making the ES.next
> cutoff. Also I agree with dherman that they have too many option issues and
> would benefit from reductions ("minimal classes", see ).
>
> On Jul 2, 2011, at 11:46 AM, Angus Croll wrote:
>
> 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.
>
>
> The difference is just induction from 1 to 2 (assuming you don't extend
> Object.prototype, which ES5 allows you to do now without breaking for-in
> loops -- from 2 to 3 if you do extend Object.prototype).
>
> Is a difference in degree really a difference in kind or meaning? I don't
> think so.
>
> Some empirical results:
>
> 5.3 Prototype Chains
> One higher-level metric is the length of an object’s prototype chain,
> which is the number of prototype objects that may potentially be
> traversed in order to find an object’s inherited property. This is
> roughly comparable to metrics of the depth of class hierarchies in
> class-based languages, such as the Depth of Inheritance (DIT) metric
> discussed in [23]. Studies of C++ programs mention a maximum
> DIT of 8 and a median of 1, whereas Smalltalk has a median of 3
> and maximum of 10. Figure 6 shows that in all but four sites, the
> median prototype chain length is 1. Note that we start our graph at
> chain length 1, the minimum. All objects except Object.prototype
> have at least one prototype, which if unspecified, defaults to the
> Object.prototype. The maximum observed prototype chain length
> is 10. The majority of sites do not seem to use prototypes for code
> reuse, but this is possibly explained by the existence of other ways
> to achieve code reuse in JavaScript (i.e., the ability to assign closures
> directly into a field of an object). The programs that do utilize
> prototypes have similar inheritance properties to Java [23].
>
> Figure 6:
>
>
> from
>
> An Analysis of the Dynamic Behavior of JavaScript Programs
> Gregor Richards Sylvain Lebresne Brian Burg Jan Vitek
> S3 Lab, Department of Computer Science, Purdue University, West Lafayette,
> IN
> {gkrichar,slebresn,bburg,jv}@cs.purdue.edu
>
>
> Unit-length prototype chain, including Object.prototype -- meaning object
> initialisers and other new Object uses, not (new C) where C is a
> user-defined function -- cover a lot of ground.
>
> But the truth is messier. Some JS libraries (and possibly compilers) use
> deeper prototype chains.
>
> Calling these a mistake across the board is a bit much.
>
>
> - 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.
>
>
> I'm as big a critic of classical OOP as anyone. No argument there, as a
> generalization.
>
> But JS has C.prototype for user-defined function C, and that makes a
> two-level prototype chain. Some cohort then go beyond that to make three- or
> deeper chains. CoffeeScript makes this all pleasant. Why shouldn't ES.next?
>
>
> - 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.
>
>
> No argument from me. Bottom-up, inductive, or constructive learning and
> system-building are usually best.
>
> We shouldn't make a religious war here. JS has "classes" in its spec for
> all the built-ins, disclosed by Object.prototype.toString().slice(8,-1).
> These are represented in-language by constructor functions. Users define
> constructor functions too.
>
> Since you are not out to prevent users from defining such "classes", why is
> syntax for the clichéd common version of prototypal inheritance beyond the
> pale?
>
>
> 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.
>
>
> Mixins require copying properties, and there's nothing lightweight (in
> usable syntax or runtime cost) in that.
>
>
> - 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.
>
>
> This is logically unsound. Java (let's skip C++, it has functional
> programming and even closures in the latest and greatest) lacks first class
> functions (historically; haven't paid attention to the latest), so it relies
> on classes.
>
> This does not prove that functional languages don't need to support classes
> as well. Many do support classes, going back to Common Lisp and other Lisps
> where macros and syntax extensions make it straightforward to provide the
> kind of sugar proposed for Harmony's classes.
>
>
> - 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.
>
>
> This an independent point. ES.next adds modules for such use-cases. That
> does not mean prototypal inheritance sugar via classes has no benefit.
>
>
> 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.
>
>
> Math is not now and never has been a class in the "represented by a
> constructor function, with a .prototype" sense. Yes, it has a [[Class]]
> internal property discoverable via Object.prototype.toString, "Math". This
> is something we're working to make meta-programmable independently of other
> interpretations of [[Class]] anyway, for DOM self-hosting. See
> http://www.wirfs-brock.com/allen/things/es5-technial-notes-and-resources
>
>
> 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.
>
>
> The concept of "chained prototypes" has been in JS from day one. Class
> syntax adds nothing new semantically.
>
>
> 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.
>
>
> Sure, we are avoiding the kitchen sink. Again, I'm not in favor of classes
> with so many open issues -- for them to make progress, we need to simplify
> and also sanity-check against how prototypal inheritance is used (e.g., with
> respect to class-side inheritance).
>
> But this does not mean Object.create is enough, any more than the module
> pattern, a leaky abstraction based on closures, obviates the need for a
> module system.
>
>
> 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.
>
>
> I think you're mixing up categories. It's not up to TC39 to change
> developers' brains by leaving out conveniences for common patterns, if those
> patterns are not inherently unsafe or otherwise bad.
>
> Even unchained prototype use-cases where there's a constructor function to
> initialize per-instance state benefit from class syntax.
>
>
> 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.
>
>
> At this point you've lost me. In no sense is class as prototypal sugar
> "classical OOP" that differs observably from prototypal inheritance in JS.
> Even class-side (constructor) inheritance would be done via <| or __proto__.
> There's nothing new and different here. No vtbls, no interfaces as in Java,
> no non-property "fields" or "final methods".
>
> I think you're mixing up good skepticism of OOP-is-all-you-need with
> classes-as-prototypal-sugar FUD. Would changing "class", the reserved word
> (we can't really unreserve and pick another), to "constructor", help? If
> not, why not?
>
> Allen's efforts with <| and generalized 'super' also reinforce the point
> that classes are prototypal inheritance sugar, and only that. Jeremy's work
> with CoffeeScript demonstrates the same point. There is no magic runtime
> implementing classical OOP differently, other than class-side (constructor)
> inheritance via  a little property-copying helper code, for want of <| or
> universal writable __proto__.
>
> I think you are protesting too much.
>
> /be
>
>
>
> 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/21657705/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: Figure 6.png
Type: image/png
Size: 58038 bytes
Desc: not available
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20110702/21657705/attachment-0001.png>


More information about the es-discuss mailing list