Classes: suggestions for improvement

# Axel Rauschmayer (14 years ago)

I really like the proposal: it is very lightweight syntactic sugar. For example, it is not that radically different from Resig’s Simple Inheritance (whose "look" I like). The "super" keyword for calling overridden methods and chaining super-constructors and the "static" keyword for defining class properties are welcome additions. Especially "super" saves a lot of boilerplate code.

Minor suggestions for improvement:

(1) The syntax for private properties still is a bit clumsy, and @ feels like wasting a nice symbol, how about using private.foo instead of private(this).foo?

(2) "public" feels superfluous in class body and the word "public" does not really denote the opposite of "static".

(3) Is "static const" possible?

This is a bit farther out: There is a use case for having a superclass and 0 or more prototypes at the same time. The former is useful for constructor chaining, the latter could be used to implement poor man’s traits. Then the prototype chain would look like this:

subTypeInstance |> SubType.prototype |> Trait1 |> Trait 2 |> SuperType.prototype

Does anybody know what Brendan meant in this txjs talk with “Classes made it (Yay, I think? Why am I sad?)”? Is he ambivalent about the proposal? Is there anything he doesn’t like?

Axel

# Brendan Eich (14 years ago)

On Jun 12, 2011, at 2:22 PM, Axel Rauschmayer wrote:

(1) The syntax for private properties still is a bit clumsy, and @ feels like wasting a nice symbol, how about using private.foo instead of private(this).foo?

No, you need private(other).foo or shorter for things like

class Point { constructor(x, y) { private x = x; private y = y; } equals(p) { return private(this).x === private(p).x && private(this).y === private(p).y; } ... }

BTW, @ is hardly "wasted" as shorthand, since the above is way too long and also requires reifying private data as an object, which we do not want (I mean, I believe no one wants).

(2) "public" feels superfluous in class body and the word "public" does not really denote the opposite of "static".

Especially when it's not the opposite anyway: "proto" would be better but it is unnecessary.

(3) Is "static const" possible?

Yes, see

This is a bit farther out: There is a use case for having a superclass and 0 or more prototypes at the same time. The former is useful for constructor chaining, the latter could be used to implement poor man’s traits.

This proposal is about prototypal inheritance sugar only. Mark split out the traits stuff for good reason, and we wouldn't want to be poor men (or women) if we could have real traits.

Does anybody know what Brendan meant in this txjs talk with “Classes made it (Yay, I think? Why am I sad?)”? Is he ambivalent about the proposal? Is there anything he doesn’t like?

You can just ask me ;-).

Something about classes in JS makes me sad, an emotional effect I can't explain fully. In part I fear the "lint brush" aspect I mentioned in the thread Irakli just followed up: class syntax will grow lots of hair over time. In part I think class is the wrong word, as cowboyd tweeted (see below).

Mainly I think we are still finding class syntax, not just the keyword, a bit hard to fit to the prototypal pattern. The super keyword in limited expression forms is no problem. The extends and prototype "Heritage" clause in the class head is ok.

The constructor flows from the prototype-methods-at-class-element-position design, but starts to rankle, if only because of the name's length. As you can see in my posts today, it seems to go downhill from there. And we're still trying to find a better syntax than the "static" keyword.

/be

(I hope this twitter converation is readable.)

cowboyd Charles Lowell For the record, I do not like the class syntax ES.next either. It's not a class, why would you call it that? #txjs 11 Jun Favorite Retweet Reply

BrendanEich BrendanEich @ @cowboyd no one could come up with a better name -- we tried. What would you call these things? 11 Jun in reply to ↑

@cowboyd Charles Lowell @BrendanEich It's a small thing, and I'll get over it, but something about "class" fills me with melancholy. 11 Jun via Twitter for Mac Favorite Retweet Reply replies ↓

BrendanEich BrendanEich @ @cowboyd yeah, me too. Melancholy about classes from a number of people has to matter. 11 Jun

# Brendan Eich (14 years ago)

On Jun 12, 2011, at 2:38 PM, Brendan Eich wrote:

(3) Is "static const" possible?

Yes, see

Oops, accidentally cut "the grammar".

ClassPropertyDefinition : static ExportableDefinition ExportableDefinition : Declaration

and Declaration : const Pattern.

# Brendan Eich (14 years ago)

On Jun 12, 2011, at 2:22 PM, Axel Rauschmayer wrote:

I really like the proposal: it is very lightweight syntactic sugar. For example, it is not that radically different from Resig’s Simple Inheritance (whose "look" I like).

There is good in the proposal, don't get me wrong. I worked on it at the end, because I believe developers want sugar for the prototypal pattern, they've said so often.

The "super" keyword for calling overridden methods and chaining super-constructors

Yes, this is good but somewhat separable from class {...}, although we need a context in which "super" makes sense as a special form.

and the "static" keyword for defining class properties are welcome additions.

Why "static" is the wrong word: there is nothing compile-time about the class properties. Classes are expressible (anonymous, even), as well as declarable in nested (generative) ways.

Using "class" does not work if one wants nested classes, although the default that binds prototype properties for ExportableDefinitions including Declarations seems like exactly the wrong default: how often do you want class Outer { class Nested {} ... } to make Nested a property of Outer.prototype, instead of a class property (Outer.Nested)?

Again, the grammatical retasking of certain Declarations to bind prototype properties (instead of lexical bindings in the class body, or perhaps class properties -- but perhaps not) seems like a mistake.

# Brendan Eich (14 years ago)

On Jun 12, 2011, at 2:38 PM, Brendan Eich wrote:

Something about classes in JS makes me sad, an emotional effect I can't explain fully. In part I fear the "lint brush" aspect I mentioned in the thread Irakli just followed up: class syntax will grow lots of hair over time. In part I think class is the wrong word, as cowboyd tweeted (see below).

Mainly I think we are still finding class syntax, not just the keyword, a bit hard to fit to the prototypal pattern. The super keyword in limited expression forms is no problem. The extends and prototype "Heritage" clause in the class head is ok.

The constructor flows from the prototype-methods-at-class-element-position design, but starts to rankle, if only because of the name's length. As you can see in my posts today, it seems to go downhill from there. And we're still trying to find a better syntax than the "static" keyword.

Let's say we can make classes mean what we want. Per the agreement to promote them into Harmony with open issues, we are "close enough".

But we still need to nail those open issues. This requires considering alternatives carefully and writing down everything pro and con. It'll be tedious work, without easy answers (at first). I'm game to do it here, although others may fear the Inbox load.

Reflecting on classes in JS, at a high level I feel we are falling into the gravity well of a dying star. It could supernova, in which case we will be burned. Or it could black-hole and we'll get rent by tides before going somewhere else ;-).

Ok, fun metaphor but I'm not totally kidding. The gravity well is created by the mass of "class expectations" from other languages, plus de-facto "prototypal" and other patterns in JS. Heavy.

# Axel Rauschmayer (14 years ago)

(1) The syntax for private properties still is a bit clumsy, and @ feels like wasting a nice symbol, how about using private.foo instead of private(this).foo?

No, you need private(other).foo or shorter for things like

class Point { constructor(x, y) { private x = x; private y = y; } equals(p) { return private(this).x === private(p).x && private(this).y === private(p).y; } ... }

BTW, @ is hardly "wasted" as shorthand, since the above is way too long and also requires reifying private data as an object, which we do not want (I mean, I believe no one wants).

What confuses me slightly is that it initially looks like private and public properties share the same namespace, but later don’t seem to. Maybe it would be better to make the different namespaces explicit:

class Point { constructor(x, y) { private @x = x; private @y = y; } equals(p) { return this. at x === p. at x && this. at y === p. at y; } ... }

Maybe something like the following would work, too:

private.x = x; ... return this.private.x === p.private.x;

# Axel Rauschmayer (14 years ago)

and the "static" keyword for defining class properties are welcome additions.

Why "static" is the wrong word: there is nothing compile-time about the class properties. Classes are expressible (anonymous, even), as well as declarable in nested (generative) ways.

Using "class" does not work if one wants nested classes, although the default that binds prototype properties for ExportableDefinitions including Declarations seems like exactly the wrong default: how often do you want class Outer { class Nested {} ... } to make Nested a property of Outer.prototype, instead of a class property (Outer.Nested)?

Again, the grammatical retasking of certain Declarations to bind prototype properties (instead of lexical bindings in the class body, or perhaps class properties -- but perhaps not) seems like a mistake.

Terminology-wise, I have always avoided the word “class” in JavaScript and used the word “type”, instead (with, roughly, constructors implementing types). I call Properties such as Math.PI type variables. Then you can also talk about subtyping (instead of subclassing).

# Brendan Eich (14 years ago)

On Jun 12, 2011, at 3:43 PM, Axel Rauschmayer wrote:

(1) The syntax for private properties still is a bit clumsy, and @ feels like wasting a nice symbol, how about using private.foo instead of private(this).foo?

No, you need private(other).foo or shorter for things like

class Point { constructor(x, y) { private x = x; private y = y; } equals(p) { return private(this).x === private(p).x && private(this).y === private(p).y; } ... }

BTW, @ is hardly "wasted" as shorthand, since the above is way too long and also requires reifying private data as an object, which we do not want (I mean, I believe no one wants).

What confuses me slightly is that it initially looks like private and public properties share the same namespace, but later don’t seem to. Maybe it would be better to make the different namespaces explicit:

class Point { constructor(x, y) { private @x = x; private @y = y;

We hardly need private, then.

The point of the declarative forms that start with keywords such as private is to declare, not express. In the equals method I wrote originally:

equals(p) { return @x === p at x && @y === p at y; }

@ is a prefix and infix operator in expressions.

} equals(p) { return this. at x === p. at x && this. at y === p. at y; }

We've been over this ground. Why require . as well as @? The prefix form for this@ is a win too.

Maybe something like the following would work, too:

private.x = x; ... return this.private.x === p.private.x;

No, ES5 allows this.private, foo.private, etc. (reserved identifiers as property names).

# Brendan Eich (14 years ago)

On Jun 12, 2011, at 3:49 PM, Axel Rauschmayer wrote:

and the "static" keyword for defining class properties are welcome additions.

Why "static" is the wrong word: there is nothing compile-time about the class properties. Classes are expressible (anonymous, even), as well as declarable in nested (generative) ways.

Using "class" does not work if one wants nested classes, although the default that binds prototype properties for ExportableDefinitions including Declarations seems like exactly the wrong default: how often do you want class Outer { class Nested {} ... } to make Nested a property of Outer.prototype, instead of a class property (Outer.Nested)?

Again, the grammatical retasking of certain Declarations to bind prototype properties (instead of lexical bindings in the class body, or perhaps class properties -- but perhaps not) seems like a mistake.

Terminology-wise, I have always avoided the word “class” in JavaScript and used the word “type”, instead (with, roughly, constructors implementing types). I call Properties such as Math.PI type variables. Then you can also talk about subtyping (instead of subclassing).

Sorry, I can't agree with this. "type" is even more of a loaded word, and a misnomer. Math is not even a constructor, never mind a type!

# Axel Rauschmayer (14 years ago)

Something about classes in JS makes me sad, an emotional effect I can't explain fully. In part I fear the "lint brush" aspect I mentioned in the thread Irakli just followed up: class syntax will grow lots of hair over time. In part I think class is the wrong word, as cowboyd tweeted (see below).

Mainly I think we are still finding class syntax, not just the keyword, a bit hard to fit to the prototypal pattern. The super keyword in limited expression forms is no problem. The extends and prototype "Heritage" clause in the class head is ok.

The constructor flows from the prototype-methods-at-class-element-position design, but starts to rankle, if only because of the name's length. As you can see in my posts today, it seems to go downhill from there. And we're still trying to find a better syntax than the "static" keyword.

Let's say we can make classes mean what we want. Per the agreement to promote them into Harmony with open issues, we are "close enough".

But we still need to nail those open issues. This requires considering alternatives carefully and writing down everything pro and con. It'll be tedious work, without easy answers (at first). I'm game to do it here, although others may fear the Inbox load.

Reflecting on classes in JS, at a high level I feel we are falling into the gravity well of a dying star. It could supernova, in which case we will be burned. Or it could black-hole and we'll get rent by tides before going somewhere else ;-).

Ok, fun metaphor but I'm not totally kidding. The gravity well is created by the mass of "class expectations" from other languages, plus de-facto "prototypal" and other patterns in JS. Heavy.

Two observations:

  • Object.create() seems to have started something truly prototypal in JavaScript that never quite got finished. If there was a way to bring more Self to JavaScript (instead of more Java, Python, or Ruby) when it comes to inheritance, I would be all for it, but it always sounded to me like most people don’t want that.

  • What I find most difficult about the current way of doing inheritance is that the constructor "is" the type, while the prototype would be a much better choice.

var SkinnedMesh = THREE.Mesh <| { constructor(geometry, materials) { super.constructor(geometry, materials);

this.identityMatrix = new THREE.Matrix4();
this.bones = [];
this.boneMatrices = [];
...

}

update(camera) { ... super.update(); } }

var sm = new SkinnedMesh(...); sm instanceof SkinnedMesh // true

The only things that change from ES5 are:

  • Adapting new and instanceof to accept objects (in addition to constructor functions)
  • Some kind of proto operator (<| in the code above)
  • super.foo(x,y) is syntactic sugar for Object.getPrototypeOf(SkinnedMesh).foo.call(this, x, y)
    • I have no idea how to get SkinnedMesh in there, but concise object literals make a similar proposal, so there must be a solution.
  • The above obviously profits from anything offered by concise object literals (and in fact already uses the more compact way to write methods).

I hope this makes sense. A side benefit would be that type/class variables (such as Math.PI) would automatically be inherited to subtypes/subclasses.

# Peter Michaux (14 years ago)

On Sun, Jun 12, 2011 at 2:38 PM, Brendan Eich <brendan at mozilla.com> wrote:

On Jun 12, 2011, at 2:22 PM, Axel Rauschmayer wrote:

Does anybody know what Brendan meant in this txjs talk with “Classes made it (Yay, I think? Why am I sad?)”? Is he ambivalent about the proposal? Is there anything he doesn’t like?

You can just ask me ;-). Something about classes in JS makes me sad, an emotional effect I can't explain fully. In part I fear the "lint brush" aspect I mentioned in the thread Irakli just followed up: class syntax will grow lots of hair over time. In part I think class is the wrong word, as cowboyd tweeted (see below).

(For some reason I read that as "a cowboy in tweed" which seems wrong and possibly a metaphor for wrapping "prototypes in classes".)

I think "class" is the wrong word also. If the syntax is just syntax then ECMAScript still won't have any new kind of "class" thing that it didn't have before.

One thing that worries me about using the word "class" is that folks will think they are getting the same type of "class" that they have in the other language the know/use/love. That won't be the case. It will a misleading facade and lead to resentment.

Peter

# Juan Ignacio Dopazo (14 years ago)

On Sun, Jun 12, 2011 at 6:38 PM, Brendan Eich <brendan at mozilla.com> wrote:

On Jun 12, 2011, at 2:22 PM, Axel Rauschmayer wrote:

(1) The syntax for private properties still is a bit clumsy, and @ feels like wasting a nice symbol, how about using private.foo instead of private(this).foo?

No, you need private(other).foo or shorter for things like

class Point { constructor(x, y) { private x = x; private y = y; } equals(p) { return private(this).x === private(p).x && private(this).y === private(p).y; } ... }

If I understand correctly the reason for needing private(this).x is because the private names proposal allows having a private name with the same name as a common property.

Also IIRC , this is a result of putting instance properties in the constructor. Because of that the private name lives in the scope of the constructor and not in the scope of the class. So would this be correct?

class Monster { private jump() { console.log('jump!'); } constructor() { this.jump(); } }

Juan

# Brendan Eich (14 years ago)

On Jun 12, 2011, at 4:54 PM, Juan Ignacio Dopazo wrote:

If I understand correctly the reason for needing private(this).x is because the private names proposal allows having a private name with the same name as a common property.

Whether private in class uses private name objects or some other unobservably-different implementation is not specified. It may not be observable even with reflection we can agree to put in the language any time soon.

Allen points out that a self-hosted debugger with VM-like stratification would want to peek at privates (as it would also at closure innards). In such scenarios, private name objects may be attractive, since they can yield to reflection (via .public, or without that substitution in a privileged "VM host" or "outer ring" trusted environment such as a debugger).

Closures for private vars have notable costs, discussed here recently, and so are not suitable in the foreseeable future. But to your point below, closures may be too closed if we are talking about the constructor.

Also IIRC , this is a result of putting instance properties in the constructor. Because of that the private name lives in the scope of the constructor and not in the scope of the class. So would this be correct?

class Monster { private jump() { console.log('jump!'); } constructor() { this.jump(); } }

Not yet specified, but possible. Here an unobservable closure around the class (the power constructor pattern, IINM) could be used to hold the prototype-available, once per class evaluation, private bindings. Or perhaps private names on the prototype object could be used, but freeze would have to skip them.

I'm not sure classes should grow to have private class or prototype variables in ES.next. Mark stripped things down to help get classes in. The one reason I come back to them: private methods for common subroutining are frequent in practice. So YAGNI doesn't work. One can always closure- or module-wrap by hand; that's the counterargument.

# Allen Wirfs-Brock (14 years ago)

On Jun 12, 2011, at 4:13 PM, Axel Rauschmayer wrote:

Two observations:

  • Object.create() seems to have started something truly prototypal in JavaScript that never quite got finished. If there was a way to bring more Self to JavaScript (instead of more Java, Python, or Ruby) when it comes to inheritance, I would be all for it, but it always sounded to me like most people don’t want that.

This is much of the motivation behind the enhanced object literal and <| proposals. They are intended to be a more usable alternative to Object.create.

  • What I find most difficult about the current way of doing inheritance is that the constructor "is" the type, while the prototype would be a much better choice.

I've been thinking a fair amount recently about prototypal inheritance in self versus what we do in JavaScript. There are a couple things I've noted. One is that while self started out as a deconstructed Smalltalk without classes, the evolution of the language and environment (like Smalltalk, it is hard to separate the two) ultimately took it to a place where you program in terms of abstractions that seem quite like Smalltalk classes. This seems roughly parallel to what we see occurring in both JS frameworks and ES.next. We find that we need a more concrete abstraction capability then naked prototype inheritance so we use prototypal inheritance to createsomething that is quite similar to Smalltalk classes but quite different from Java classes).

Another thing I've noted is that in creating its abstraction facilities, self makes extensive use of multiple inheritance. One might argue that by starting with deconstructing classes self was able to successfully incorporate multiple inheritance into its abstraction model. This is something that was never done successfully for classical Smalltalk. I don't know how successful self actually was in this regard as I've never done any actual self programming. However, MI seems to have been used extensive in creating the self libraries and environment.

AT first there seems to be a big difference between how self and JavaScript approach object creation. In self, you create an object by copying and what copying means is actually the responsibility of the object that is being copied. By default copy means make a new object that directly inherits from the object it is copied from. Prototype objects are what most typically get copied to create new instances.

So where in JavaScript we would say: var p = new Person(); to create an instance of a person in self one would say: p = ProtoPerson copy.

and the default definition of the copy method that is inherited from the top of the inheritance hierarchy is the equivalent (in JavaScript terms) of: Object.prototype.copy = function() {return Object.create(this)};

in other words copy is does prototypal inheritance in self.

Of course, this doesn't work very well if the prototype contains non-shareable mutable state. This is accounted for by over-riding the copy in prototype objects to appropriately deal with such non-sharable state. For example: ProtoPerson.copy = function () { let newPerson = super.copy(); //use super similarly to what is currently proposed for ES.next; newPerson.siblings = ProtoCollection.copy(); // assumes siblings is a mutable, non sharable property return newPerson; };

This is essentially the same thing you would do in a JavaScript Person constructor: function Person() { this.siblings = new Collection(); return this }

So, there is pretty much a directly correspondence between a self copy method and a JavaScript constructor function. However, there is definitely a difference of emphasis seen here. In self, it is the prototype object that is the focus of attention. In traditional JavaScript it is the constructor object.

For people who want to know more about self see selflanguage.org/documentation/published/parents-shared-parts.html and particularly selflanguage.org/documentation/published/parents-shared-parts.html and selflanguage.org/documentation/published/organizing-programs.html

# Axel Rauschmayer (14 years ago)

So, there is pretty much a directly correspondence between a self copy method and a JavaScript constructor function. However, there is definitely a difference of emphasis seen here. In self, it is the prototype object that is the focus of attention. In traditional JavaScript it is the constructor object.

So you argue that a constructor C corresponds to an instance, a prototype P corresponds to a class (for lack of a better term). And instead of copying the prototypical instance, you “send the message ‘new’” to C. But then instanceof is still weird – the right hand side should be the prototype and not the constructor.

I’ve only got one use case for this, but “class methods” would also work better if they could be attached to the prototype (and subject to inheritance) instead of the constructor.

Take a root class Class that knows how to extend classes, including itself. For example:

var MySuperClass = Class.extend(...); var MySubClass = MySuperClass.extend(...);

To implement something like this in ES5, you have to manually add the extend() method to each newly created class, because a constructor does not inherit methods that are attached to its super-constructor.

Well, this might be a largely academic discussion and class literals are probably a good enough compromise. But class literals being so similar to object literals, I like the idea of making do with just concise object literals and a proto operator.

Axel

# Allen Wirfs-Brock (14 years ago)

On Jun 12, 2011, at 8:46 PM, Axel Rauschmayer wrote:

So, there is pretty much a directly correspondence between a self copy method and a JavaScript constructor function. However, there is definitely a difference of emphasis seen here. In self, it is the prototype object that is the focus of attention. In traditional JavaScript it is the constructor object.

So you argue that a constructor C corresponds to an instance, a prototype P corresponds to a class (for lack of a better term). And instead of copying the prototypical instance, you “send the message ‘new’” to C.

The correspondence is not quite that straight forward. A prototype P, as used in self, does seem to frequently subsume the role of a class. A constructor generally corresponds to the copy method of such a prototype.

But then instanceof is still weird – the right hand side should be the prototype and not the constructor.

Instanceof seems a artifact of trying to use constructors in the role of classes. The corresponding operation to instanceof would be childOf: (meaning inherits from) but self doesn't appear to actually have this without getting a mirror (entering the reflection subsystem). In Smalltalk class inclusion testing, while possible, was generally frowned upon. Behavior testing (send isFoo if you want to see if an object has Foo behavior) was the preferred pattern.

I’ve only got one use case for this, but “class methods” would also work better if they could be attached to the prototype (and subject to inheritance) instead of the constructor.

Take a root class Class that knows how to extend classes, including itself. For example:

var MySuperClass = Class.extend(...); var MySubClass = MySuperClass.extend(...);

To implement something like this in ES5, you have to manually add the extend() method to each newly created class, because a constructor does not inherit methods that are attached to its super-constructor.

This appears to be a situation where self would use multiple parents.

# Brendan Eich (14 years ago)

On Jun 12, 2011, at 8:46 PM, Axel Rauschmayer wrote:

I’ve only got one use case for this, but “class methods” would also work better if they could be attached to the prototype (and subject to inheritance) instead of the constructor.

We had a thread about this, because Ruby and CoffeeScript (which translates to JS and copies properties to do "constructor inheritance") both support class method inheritance.

Putting class methods on the prototype mixes up is-a relations, making the class constructor delegate to the class prototype. That breaks constructor is-a function in general. Better to have two parallel proto-chains, one from subclass prototype to superclass prototype, the other from subclass constructor to superclass constructor.

# Axel Rauschmayer (14 years ago)

Excellent points, thanks! Wasn’t aware that Smalltalk did duck typing, but it must make things much more generic.

Note: IIRC, Self calls its prototypical instances “prototypes”. What JavaScript calls a prototype (both the relation and the objects forming the right-hand sides of such a relation) is called a parent in Self. But that does not affect your arguments.

The correspondence is not quite that straight forward. A prototype P, as used in self, does seem to frequently subsume the role of a class. A constructor generally corresponds to the copy method of such a prototype.

Isn’t that the illusion that class literals aim to create? That a class is actually a single construct, an object C with a method construct() and that you can apply the new operator to that object? new C(x,y) would perform the following steps:

  • Create a new instance o whose prototype is C.
  • Invoke o.construct(x,y)

Maybe "initialize" would be a better name than "construct", then.

Couldn’t that illusion be turned into how things are actually done?

# Kam Kasravi (14 years ago)

On Jun 13, 2011, at 1:55 AM, Axel Rauschmayer <axel at rauschma.de> wrote:

Excellent points, thanks! Wasn’t aware that Smalltalk did duck typing, but it must make things much more generic.

Note: IIRC, Self calls its prototypical instances “prototypes”. What JavaScript calls a prototype (both the relation and the objects forming the right-hand sides of such a relation) is called a parent in Self. But that does not affect your arguments.

The correspondence is not quite that straight forward. A prototype P, as used in self, does seem to frequently subsume the role of a class. A constructor generally corresponds to the copy method of such a prototype.

Isn’t that the illusion that class literals aim to create? That a class is actually a single construct, an object C with a method construct() and that you can apply the new operator to that object? new C(x,y) would perform the following steps:

  • Create a new instance o whose prototype is C.
  • Invoke o.construct(x,y)

Maybe "initialize" would be a better name than "construct", then.

Couldn’t that illusion be turned into how things are actually done?

Indeed a number of frameworks use 'initialize' for their 'ctor'. I imagine this has been heavily discussed within TC39, but perhaps some of the rational has not made es-discuss. Certain unused ascii characters may be a candidate, for example I believe C++ uses ~ for their destructor, analogously a '^' for the ctor might be a good replacement given its semantics in a regex (start of pattern).

class Monster { ^(health) { private health = health } }

I believe this still renders the grammar LR(1), however given the symbols used for 'concise object literal extensions' (harmony:concise_object_literal_extensions) this may be too much.

# Juan Ignacio Dopazo (14 years ago)

On Mon, Jun 13, 2011 at 12:01 PM, Kam Kasravi <kamkasravi at yahoo.com> wrote:

On Jun 13, 2011, at 1:55 AM, Axel Rauschmayer <axel at rauschma.de> wrote:

Indeed a number of frameworks use 'initialize' for their 'ctor'. I imagine this has been heavily discussed within TC39, but perhaps some of the rational has not made es-discuss.

It was posted somewhere... The rationale is that 'constructor' is already a

property of the prototype that points to the constructor function.

function Test() {} (Test.prototype.constructor === Test) // true

It was chosen to replace 'new' because o.new() is correct under ES5.

On Sun, Jun 12, 2011 at 10:17 PM, Brendan Eich <brendan at mozilla.com> wrote:

I'm not sure classes should grow to have private class or prototype variables in ES.next. Mark stripped things down to help get classes in. The one reason I come back to them: private methods for common subroutining are frequent in practice. So YAGNI doesn't work. One can always closure- or module-wrap by hand; that's the counterargument.

/be

I'm not sure that's a counterargument. The whole point of the classes

proposal is to simplify the use of a common pattern. Private methods for subroutines are a very common use case.

Juan

# Brendan Eich (14 years ago)

On Jun 13, 2011, at 8:41 AM, Juan Ignacio Dopazo wrote:

On Sun, Jun 12, 2011 at 10:17 PM, Brendan Eich <brendan at mozilla.com> wrote:

I'm not sure classes should grow to have private class or prototype variables in ES.next. Mark stripped things down to help get classes in. The one reason I come back to them: private methods for common subroutining are frequent in practice. So YAGNI doesn't work. One can always closure- or module-wrap by hand; that's the counterargument.

/be

I'm not sure that's a counterargument. The whole point of the classes proposal is to simplify the use of a common pattern. Private methods for subroutines are a very common use case.

Agreed. The counter-argument and the minimizing of the proposal are all about what can be done now, vs. later. Not sure when later is, perhaps even during ES.next spec construction. It is an open issue.

# Kam kasravi (14 years ago)

On Jun 12, 2011, at 10:49 PM, Brendan Eich <brendan at mozilla.com> wrote:

On Jun 12, 2011, at 8:46 PM, Axel Rauschmayer wrote:

I’ve only got one use case for this, but “class methods” would also work better if they could be attached to the prototype (and subject to inheritance) instead of the constructor.

We had a thread about this, because Ruby and CoffeeScript (which translates to JS and copies properties to do "constructor inheritance") both support class method inheritance.

Putting class methods on the prototype mixes up is-a relations, making the class constructor delegate to the class prototype. That breaks constructor is-a function in general. Better to have two parallel proto-chains, one from subclass prototype to superclass prototype, the other from subclass constructor to superclass constructor.

Is the constructor calling implicit if not specified? For example both c++ and java will call super() implicitly if there is no explicit call for the subtype constructor.

# Brendan Eich (14 years ago)

On Jun 13, 2011, at 10:33 AM, Kam kasravi wrote:

On Jun 12, 2011, at 10:49 PM, Brendan Eich <brendan at mozilla.com> wrote:

On Jun 12, 2011, at 8:46 PM, Axel Rauschmayer wrote:

I’ve only got one use case for this, but “class methods” would also work better if they could be attached to the prototype (and subject to inheritance) instead of the constructor.

We had a thread about this, because Ruby and CoffeeScript (which translates to JS and copies properties to do "constructor inheritance") both support class method inheritance.

Putting class methods on the prototype mixes up is-a relations, making the class constructor delegate to the class prototype. That breaks constructor is-a function in general. Better to have two parallel proto-chains, one from subclass prototype to superclass prototype, the other from subclass constructor to superclass constructor.

Is the constructor calling implicit if not specified? For example both c++ and java will call super() implicitly if there is no explicit call for the subtype constructor.

You're asking a question about something completely different. Whether class methods are inherited has no bearing on super call automation.

The classes proposal does not automate super calling. It's best for the user to be explicit. Guessing and passing no actual arguments is like to go wrong. JS has memory safety so the problem caused by a missing super-constructor call is a runtime value error.

# Bob Nystrom (14 years ago)

On Sun, Jun 12, 2011 at 2:38 PM, Brendan Eich <brendan at mozilla.com> wrote:

Something about classes in JS makes me sad, an emotional effect I can't explain fully.

<philosophical>

I'm one of the biggest fans of this class proposal, and I feel a twinge of that sadness too. I look at it as JS taking a step away from Scheme and towards Common Lisp.

I think one of the big reasons people love Javascript is that it has the same appeal of old school LEGOs: it gives you just a few kinds of pieceswww.brickset.com/detail/?Set=6166-1but you can combine

them in a huge variety of fashions to make all sorts of novel things. Adding class syntax feels a bit like how LEGO pieces started to get more specializedshop.lego.com/ByTheme/Product.aspx?p=7592&cn=643&d=622 .

As a creative-at-play, specialization like that sucks. You're taking away * my* ability to invent something new and replacing it with some ready-made thing that I can't modify. However, as a pragmatic person trying to get work done, this a win. If it's my job to make LEGO cars, a prebuilt chassis makes my job easier and faster.

Since JS is used by working programmers who just want to ship solid code, I think it's helpful to have features like this that encode common patterns and make them easier to express. I look at class syntax as a pre-built kit for the kinds of things we find ourselves having to make from scratch over and over again. That's great because, honestly, I'm not innovating on "how to define reusable kinds of entities" in JS everyday. I mostly follow the same constructor+prototype pattern that many of us do. So if I can have an ready-to-use syntax for that, it means less time typing that boilerplate over and over, and more of my time spent on the things I am innovating on: user experience, libraries, etc.

At the same time, it's worth remembering that class syntax doesn't take any toys away from you. You still have all of the JS primitives you know and love to play with, and if classes aren't a good fit for you, you're always free to go your own path. In that sense, they're more like classes in C++ than Java: they enshrine a common pattern but don't rebuild the entire language around them. Like C++, you can use them where they make sense and not where they don't.

</philosophical>

In part I think class is the wrong word, as cowboyd tweeted (see below).

Agreed. "class" isn't ideal, but it's probably the best we have. It carries a lot of baggage, some of which is helpful and some of which isn't. I think most of the pragmatic baggage is helpful (things you make with this class proposal behave pretty similarly to classes in other languages) but the conceptual baggage isn't: people hear "class" and think we're trying to turn JS into Java, which for many is a short hop away from COBOL and having to wear a suit to work. No one wants that to happen to JS.

# Brendan Eich (14 years ago)

+1. Very nicely put.

# Brendan Eich (14 years ago)

On Jun 13, 2011, at 12:26 PM, Brendan Eich wrote:

+1. Very nicely put.

/be

One more thought:

</philosophical>

In part I think class is the wrong word, as cowboyd tweeted (see below).

Agreed. "class" isn't ideal, but it's probably the best we have. It carries a lot of baggage, some of which is helpful and some of which isn't. I think most of the pragmatic baggage is helpful (things you make with this class proposal behave pretty similarly to classes in other languages)

The language to emulate is Smalltalk, though. People may not often think "classes in JS are like classes in Smalltalk", I'm afraid. It may be that they're more likely to think of Java.

Ruby as a Smalltalk heir may be worth studying. The inherited class methods idea is common to Smalltalk and Ruby. I do not think we should argue from Java on this point, or others. But however we argue, it may not matter. Classes in JS will probably remind a fair number of people of Java, and that (along with JS's marketing-scam of a name :-P) is unfortunate.

# Peter Michaux (14 years ago)

On Mon, Jun 13, 2011 at 12:31 PM, Brendan Eich <brendan at mozilla.com> wrote:

The language to emulate is Smalltalk, though.

+1 to that; however, the ES class proposal is not very similar to Smalltalk classes. Others are far more qualified to enumerate the differences than I am.

For example, how can we do desugared class variable and method inheritance?

Peter

# felix (14 years ago)

How about using "prototype" or "proto" as the keyword instead of "class"?

It's a declaration of a prototypical object used to generate other objects.

"prototype" is already a familiar word to JS programmers; this is just extending its use into a new but similar context.

"prototype" has a looser, more script-y feel than "class".

"prototype" has less baggage than "class"; JS is likely to be the only prototypal-inheritance language that most programmers know.

"proto Point { }" reads well in English, it's a proto-Point.

# Bob Nystrom (14 years ago)

On Tue, Jun 14, 2011 at 1:05 PM, felix <felix8a at gmail.com> wrote:

How about using "prototype" or "proto" as the keyword instead of "class"?

It's a declaration of a prototypical object used to generate other objects.

"prototype" is already a familiar word to JS programmers; this is just extending its use into a new but similar context.

"prototype" has a looser, more script-y feel than "class".

"prototype" has less baggage than "class"; JS is likely to be the only prototypal-inheritance language that most programmers know.

"proto Point { }" reads well in English, it's a proto-Point.

I think that's been considered before. My complaint with it is that Point * isn't* a prototype. It's a constructor function whose .prototype property is the prototype. In other words, the object bound to the name Point isn't the prototypical point. It's a constructor/class-thing/type-object kind of thing. It owns the Point prototype, but isn't it itself.

"class" isn't a perfect term for it, but it's not a bad one. Point is a thing that lets you create instances that all have certain properties in common. It can be used in instanceof checks to see if an object is of its type. That sounds a good bit like a class to me, at least informally.

Pragmatically, many experienced JS developers already refer to constructor functions as defining classes, and a number of existing frameworks use that terminology for their inheritance systems. Using the class keyword (which is conveniently reserved just for this use) builds on that.

# felix (14 years ago)

On Tue, Jun 14, 2011 at 13:21, Bob Nystrom <rnystrom at google.com> wrote:

On Tue, Jun 14, 2011 at 1:05 PM, felix <felix8a at gmail.com> wrote:

How about using "prototype" or "proto" as the keyword instead of "class"?

It's a declaration of a prototypical object used to generate other objects.

"prototype" is already a familiar word to JS programmers; this is just extending its use into a new but similar context.

"prototype" has a looser, more script-y feel than "class".

"prototype" has less baggage than "class"; JS is likely to be the only prototypal-inheritance language that most programmers know.

"proto Point { }" reads well in English, it's a proto-Point.

I think that's been considered before. My complaint with it is that Point isn't a prototype. It's a constructor function whose .prototype property is the prototype. In other words, the object bound to the name Point isn't the prototypical point. It's a constructor/class-thing/type-object kind of thing. It owns the Point prototype, but isn't it itself.

Hm, by that argument "class" isn't a particularly good term either, since the thing created is not a class, it's a thing that generates objects that can be considered instances of a class. Maybe something like "factory" would be a better term then?

# Bob Nystrom (14 years ago)

On Tue, Jun 14, 2011 at 1:34 PM, felix <felix8a at gmail.com> wrote:

I think that's been considered before. My complaint with it is that Point isn't a prototype. It's a constructor function whose .prototype property is the prototype. In other words, the object bound to the name Point isn't the prototypical point. It's a constructor/class-thing/type-object kind of thing. It owns the Point prototype, but isn't it itself.

Hm, by that argument "class" isn't a particularly good term either, since the thing created is not a class, it's a thing that generates objects that can be considered instances of a class.

That's actually a pretty close definition of a class in other dynamic languages. In Smalltalk, Ruby, and Python, classes are objects that have methods to let you create instances of themselves.

# felix (14 years ago)

On Tue, Jun 14, 2011 at 13:46, Bob Nystrom <rnystrom at google.com> wrote:

On Tue, Jun 14, 2011 at 1:34 PM, felix <felix8a at gmail.com> wrote:

I think that's been considered before. My complaint with it is that Point isn't a prototype. It's a constructor function whose .prototype property is the prototype. In other words, the object bound to the name Point isn't the prototypical point. It's a constructor/class-thing/type-object kind of thing. It owns the Point prototype, but isn't it itself.

Hm, by that argument "class" isn't a particularly good term either, since the thing created is not a class, it's a thing that generates objects that can be considered instances of a class.

That's actually a pretty close definition of a class in other dynamic languages. In Smalltalk, Ruby, and Python, classes are objects that have methods to let you create instances of themselves.

Then what's the problem with calling it a "proto" instead of a "class"? Ok, it's not the same thing as x.prototype or x.proto, but this doesn't seem to me like it would be a big source of confusion, and it seems to me less confusing than "class" baggage.

# Bob Nystrom (14 years ago)

On Tue, Jun 14, 2011 at 1:57 PM, felix <felix8a at gmail.com> wrote:

On Tue, Jun 14, 2011 at 13:46, Bob Nystrom <rnystrom at google.com> wrote:

On Tue, Jun 14, 2011 at 1:34 PM, felix <felix8a at gmail.com> wrote:

Hm, by that argument "class" isn't a particularly good term either, since the thing created is not a class, it's a thing that generates objects that can be considered instances of a class.

That's actually a pretty close definition of a class in other dynamic languages. In Smalltalk, Ruby, and Python, classes are objects that have methods to let you create instances of themselves.

Then what's the problem with calling it a "proto" instead of a "class"?

Sorry, I probably wasn't clear before. What I was getting at is that the thing that "class" creates is pretty much like a class in other dynamic languages. If you do this in JS:

class Point {}

The end result is a Point object that works very much like a "class" in Python, Ruby, or Smalltalk. From that angle "class" is a pretty good keyword to use.

Ok, it's not the same thing as x.prototype or x.proto, but this doesn't seem to me like it would be a big source of confusion, and it seems to me less confusing than "class" baggage.

Prototypes are already a large source of confusion in JS. They're an uncommon feature in programming languages, and JS's use of them makes them more obscure.

Consider:

function Point(x, y) { this.x = x; this.y = y; } var p = new Point(1, 2);

Ask many JS programmers what p's prototype is and they'll say Point. You and I know it's actually Point.prototype. Ask if p "inherits" from Point and many will say "yes". JS uses "prototype" to mean two distinct things: 1) the object associated with a constructor function that's used as the prototypical instance of objects created by that constructor and 2) the object an object inherits from. (Self uses "parent" for the latter, which makes things less confusing.)

Using "proto" to define a constructor would make that even murkier. If I did:

proto Point(x, y) { this.x = x; this.y = y; } var p = new Point(1, 2);

That implies (to me at least) that Point is a "prototype" (which it of course isn't, since nothing is inheriting from it at all). I fear then people would start thinking "prototype" means the constructor object itself. Eek!

# Allen Wirfs-Brock (14 years ago)

On Jun 14, 2011, at 1:34 PM, felix wrote:

On Tue, Jun 14, 2011 at 13:21, Bob Nystrom <rnystrom at google.com> wrote:

On Tue, Jun 14, 2011 at 1:05 PM, felix <felix8a at gmail.com> wrote:

How about using "prototype" or "proto" as the keyword instead of "class"?

It's a declaration of a prototypical object used to generate other objects.

"prototype" is already a familiar word to JS programmers; this is just extending its use into a new but similar context.

"prototype" has a looser, more script-y feel than "class".

"prototype" has less baggage than "class"; JS is likely to be the only prototypal-inheritance language that most programmers know.

"proto Point { }" reads well in English, it's a proto-Point.

I think that's been considered before. My complaint with it is that Point isn't a prototype. It's a constructor function whose .prototype property is the prototype. In other words, the object bound to the name Point isn't the prototypical point. It's a constructor/class-thing/type-object kind of thing. It owns the Point prototype, but isn't it itself.

Hm, by that argument "class" isn't a particularly good term either, since the thing created is not a class, it's a thing that generates objects that can be considered instances of a class. Maybe something like "factory" would be a better term then?

There are many definitions of "class" but most of the better, non-langauge specific ones are similar to the Wikipedia definition en.wikipedia.org/wiki/Class_(computer_science) which starts out "In object-oriented programming, a class is a construct that is used as a blueprint to create instances of the class...A class defines constituent members which enable class instances to have state and behavior...."

This certainly fits the current ES.next class proposal. We have a language construct (the class definition) that defines the constituent state and behavior members (properties) of class instances. Beyond that, we see features within the normal range of variations that are common for languages that have a class construct. We define (optionally) name a constructor function rather than a class object but that still fits the basic definition. The fact, that shared instance members are factored into a separate object (the prototype) is mostly an design detail of the language and doesn't impact the basic meaning of "class".

The "Run-time Representation" section of the same article is also relevant. It says: "As a data type, a class is usually considered as a compile-time construct. A language may also support prototype or factory metaobjects that represent run-time information about classes, or even represent metadata that provides access to reflection facilities and ability to manipulate data structure formats at run-time. Many languages distinguish this kind of run-time type information about classes from a class on the basis that the information is not needed at run-time. Some dynamic languages do not make strict distinctions between run-time and compile-time constructs, and therefore may not distinguish between metaobjects and classes."

In the ES.next proposal, a class is a compile-time construct of the language, it really doesn't exist at runtime. Instead at runtime we have the constructor/prototype pair of objects that are used together to create instances of the class.

# Axel Rauschmayer (14 years ago)

JS uses "prototype" to mean two distinct things:

  1. the object associated with a constructor function that's used as the prototypical instance of objects created by that constructor and
  2. the object an object inherits from. (Self uses "parent" for the latter, which makes things less confusing.)

I would rephrase (1) as follows:

  • The object associated with a constructor function that becomes the /prototype/ of all instances created by the constructor. That is, it is an object that all instances inherit from.

The term “prototypical instance” might convey the wrong image, as Point.prototype is more of a meta-instance.

But in general: point taken. I do like the idea to use “factory”, but “class” might be close enough to people’s expectations that it works. What I find complicated is that what would be a class in, say, Python, is two constructs in JavaScript: (1) the constructor produces and initializes instances, (2) the prototype contains shared data.

Axel

# Allen Wirfs-Brock (14 years ago)

On Jun 14, 2011, at 3:00 PM, Axel Rauschmayer wrote:

But in general: point taken. I do like the idea to use “factory”, but “class” might be close enough to people’s expectations that it works. What I find complicated is that what would be a class in, say, Python, is two constructs in JavaScript: (1) the constructor produces and initializes instances, (2) the prototype contains shared data.

In the ES.next class proposal the constructor function and the prototype are simply constituents parts of a single class declaration. This definition actually turns into many objects in addition to the constructor function and the prototype. For example, there are also all the individual method function objects.

The fact that a single language construct generates multiple runtime objects isn't unusual. For example a Smalltalk class turns into a class object (roughly corresponding to the JS constructor), an instance method dictionary (roughly corresponding to the JS prototype), a metaclass object and a metaclass method dictionary (together, roughly corresponding to constructor properties), a class variable pool dictionary (roughly corresponding to any closure captured JS state that is shared by the constructor and instances), and at least one object per class or instance method.

# Brendan Eich (14 years ago)

On Jun 13, 2011, at 10:07 PM, Peter Michaux wrote:

On Mon, Jun 13, 2011 at 12:31 PM, Brendan Eich <brendan at mozilla.com> wrote:

The language to emulate is Smalltalk, though.

+1 to that; however, the ES class proposal is not very similar to Smalltalk classes. Others are far more qualified to enumerate the differences than I am.

Smalltalk had instance-private instance variables, the classes proposal has class-private instance variables. That's a difference, but not fatal to the argument that Harmony classes are closer to Smalltalk than to other languages.

The other big difference you note below (class method inheritance) is still an open issue.

Reflection differs in its details, and Allen has blogged about mirror-based systems that go beyond what is in ES5. Whatever we do, Harmony class instances will be objects on which you can reflect using ES5's Object.getOwnPropertyNames, for the public properties, and so forth.

For example, how can we do desugared class variable and method inheritance?

We are discussing class method inheritance still. I added it as an open issue.

Allen sent a reply today listing correspondences between Smalltalk class parts or sub-objects and Harmony class parts/sub-objects, which included "a class variable pool dictionary (roughly corresponding to any closure captured JS state that is shared by the constructor and instances)". Is that what you meant by "desugared class variable ... inheritance"?

Probably you should call out other differences you're concerned about, if any.

# Breton Slivka (14 years ago)

Perhaps I am overlooking something obvious, but is there something wrong with calling a constructor function constructor, rather than class or proto or prototype?

# Brendan Eich (14 years ago)

On Jun 14, 2011, at 8:51 PM, Breton Slivka wrote:

Perhaps I am overlooking something obvious, but is there something wrong with calling a constructor function constructor, rather than class or proto or prototype?

Yes, we've been over this in various places, probably need it recorded on the proposal page. 'constructor' is

(1) not reserved, so we cannot support anonymous class expressions written '... constructor {...}' where ... is left expression context; (2) too long.

Anyway, it's not just the constructor that the syntax defines or expresses, as Allen and Bob have pointed out. The prototype properties are the body elements. The constructor function is named 'constructor' on the prototype, based on ES1-5 (user-defined constructor functions each have a .prototype property whose .constructor refers to that function). There are several objects or sets of property or even variable (not yet agreed as being observable as properties -- the private instance variables) defined by one special form.

Starting that form with 'class' is not the worst design, and arguably it remains the best. 'class' is reserved and it has precedent in Smaltalk, Ruby, Python, and other dynamic languages.

# Axel Rauschmayer (14 years ago)

Ah, cool, I hadn’t noticed that. I read new SkinnedMesh.constructor(aGeo, aMat) as new SkinnedMesh().constructor(aGeo, aMat) I also missed the following sentence in Allen’s proposal:

BTW, I believe that somebody else recently on one of these threads also suggested allowing the new operator to be applied to any object so feel free to take credit.

I do agree that this beats inventing a new protocol. Very clever.