class sugar

# Peter Michaux (14 years ago)

JavaScript has two well-known ways of doing object construction that could be argued to be class-like. (Trying to be careful with wording here.) There is the new/prototype/this-based system and there is the closure-based system.

new/prototype/this-based system -----------------------

function Point(x, y) { this.x = x; this.y = y; };

Point.prototype.getDistance = function() { return Math.sqrt(this.x * this.x + this.y * this.y); };

closure-based system ----------------------------------

function makePoint(x, y) { return { getDistance: function() { return Math.sqrt(x * x + y * y); } }; }

The classes strawman is proposing terse syntax to make the new/prototype/this-based system more aesthetic.

harmony:classes

Introducing class syntax will be one of the most monumental changes ever made to ECMAScript and I suggest that unfortunately the proposal is targeting the wrong version of creating constructors. I've found the closure-based system more compelling than the new/prototype/this-based system. My memory even makes me think that this list was heading in the direction of sugaring the closure-based system in 2008.

www.mail-archive.com/[email protected]/msg00335.html

Was using class syntax to sugar the closure-based system thrown out as a possibility for some reason?

Peter

# Mark S. Miller (14 years ago)

On Fri, Jun 3, 2011 at 9:43 PM, Peter Michaux <petermichaux at gmail.com>wrote:

JavaScript has two well-known ways of doing object construction that could be argued to be class-like. (Trying to be careful with wording here.) There is the new/prototype/this-based system and there is the closure-based system.

new/prototype/this-based system -----------------------

function Point(x, y) { this.x = x; this.y = y; };

Point.prototype.getDistance = function() { return Math.sqrt(this.x * this.x + this.y * this.y); };

which can be expressed in classes as:

class Point { constructor(x, y) { public x = x; public y = y; } getDistance() { return Math.sqrt(this.x * this.x + this.y * this.y); } }

closure-based system ----------------------------------

function makePoint(x, y) { return { getDistance: function() { return Math.sqrt(x * x + y * y); } }; }

which can be expressed in classes as:

class Point { constructor(x, y) { public getDistance() { return Math.sqrt(x * x + y * y); } } }

The classes strawman is proposing terse syntax to make the new/prototype/this-based system more aesthetic.

harmony:classes

Introducing class syntax will be one of the most monumental changes ever made to ECMAScript and I suggest that unfortunately the proposal is targeting the wrong version of creating constructors. I've found the closure-based system more compelling than the new/prototype/this-based system. My memory even makes me think that this list was heading in the direction of sugaring the closure-based system in 2008.

www.mail-archive.com/[email protected]/msg00335.html

Was using class syntax to sugar the closure-based system thrown out as a possibility for some reason?

Hi Peter, your memory is correct and the classes design has had a tortuous history responding to many pressures. As you see from my rewrite of your two examples above, the design we ended up promoting to harmony can express both. While I agree that the objects-as-closure approach is more elegant, it is less common. Most class-like code today is expressed in the prototype/this-based style. As discussion continued among various committee members, it became clear that a class proposal that served only the objects-as-closures proposal could not achieve consensus. It also became clear that we could adopt a proposal that served only the prototype/this style. I'm glad to say that we did much better than that.

Some great virtue of the classes proposal that we adopted are that

  • it can express the more common prototype/this-based style in a terse and clear manner.
  • code in the prototype/this-based style of classes can trivially be as efficient as the corresponding common pattern is today, without arduous VM changes
  • classes can interoperate in both directions with old conventional prototype/this-based code
  • objects-as-closures can still be expressed
  • both patterns support string encapsulation a) prototype and instance methods can access "private(this)"-based class-private instance variables. b) instance methods can access lexically captured instance-private instance variables
  • both patterns support high integrity in the context of a "const class".
  • And perhaps most important, that it serves all these purposes with a very simple design.

Personally, for new code that does not need to interoperate with old prototype/this-based code and does not need to be super high performance, I will always use the objects-as-closures pattern. For users like us, this accepted class proposal has the following disadvantages:

  • code in the objects-as-closure style is more verbose than it would have been in earlier proposals, but not too bad.
  • code in the objects-as-closure style is less likely to be efficient, because the efficiency already supported by the other style removes the pressure implement the optimizations needed to make the objects-as-closure style efficient. (Of course, these optimizations are no less possible than they were in the earlier proposals, it's just that they're less likely to happen.)

Altogether, given my weightings of these pros and cons, I am extremely happy with these tradeoffs.

# Mark S. Miller (14 years ago)

On Sat, Jun 4, 2011 at 12:04 AM, Mark S. Miller <erights at google.com> wrote:

closure-based system ----------------------------------

function makePoint(x, y) { return { getDistance: function() { return Math.sqrt(x * x + y * y); } }; }

which can be expressed in classes as:

class Point { constructor(x, y) { public getDistance() { return Math.sqrt(x * x + y * y); } } }

Btw, I'd like to thank you again for having made the suggestion at < esdiscuss/2008-November/008185> for

supporting objects-as-closure with a "public" annotated declaration in what was essentially a block body. This suggestion survived through many class strawmen and is now in the promoted proposal.

# Mark S. Miller (14 years ago)

On Sat, Jun 4, 2011 at 12:04 AM, Mark S. Miller <erights at google.com> wrote:

On Fri, Jun 3, 2011 at 9:43 PM, Peter Michaux <petermichaux at gmail.com>wrote:

JavaScript has two well-known ways of doing object construction that could be argued to be class-like. (Trying to be careful with wording here.) There is the new/prototype/this-based system and there is the closure-based system.

new/prototype/this-based system -----------------------

function Point(x, y) { this.x = x; this.y = y; };

Point.prototype.getDistance = function() { return Math.sqrt(this.x * this.x + this.y * this.y); };

which can be expressed in classes as:

class Point { constructor(x, y) { public x = x; public y = y; } getDistance() { return Math.sqrt(this.x * this.x + this.y * this.y); } }

closure-based system ----------------------------------

function makePoint(x, y) { return { getDistance: function() { return Math.sqrt(x * x + y * y); } }; }

which can be expressed in classes as:

class Point { constructor(x, y) { public getDistance() { return Math.sqrt(x * x + y * y); } } }

The classes strawman is proposing terse syntax to make the new/prototype/this-based system more aesthetic.

harmony:classes

Introducing class syntax will be one of the most monumental changes ever made to ECMAScript and I suggest that unfortunately the proposal is targeting the wrong version of creating constructors. I've found the closure-based system more compelling than the new/prototype/this-based system. My memory even makes me think that this list was heading in the direction of sugaring the closure-based system in 2008.

www.mail-archive.com/[email protected]/msg00335.html

Was using class syntax to sugar the closure-based system thrown out as a possibility for some reason?

Hi Peter, your memory is correct and the classes design has had a tortuous history responding to many pressures. As you see from my rewrite of your two examples above, the design we ended up promoting to harmony can express both. While I agree that the objects-as-closure approach is more elegant, it is less common. Most class-like code today is expressed in the prototype/this-based style. As discussion continued among various committee members, it became clear that a class proposal that served only the objects-as-closures proposal could not achieve consensus. It also became clear that we could adopt a proposal that served only the prototype/this style. I'm glad to say that we did much better than that.

Some great virtue of the classes proposal that we adopted are that

  • it can express the more common prototype/this-based style in a terse and clear manner.
  • code in the prototype/this-based style of classes can trivially be as efficient as the corresponding common pattern is today, without arduous VM changes
  • classes can interoperate in both directions with old conventional prototype/this-based code
  • objects-as-closures can still be expressed
  • both patterns support string encapsulation

Should be: strong encapsulation

# Peter Michaux (14 years ago)

On Sat, Jun 4, 2011 at 12:04 AM, Mark S. Miller <erights at google.com> wrote:

Hi Peter, your memory is correct and the classes design has had a tortuous history responding to many pressures. As you see from my rewrite of your two examples above, the design we ended up promoting to harmony can express both.

Thanks for those examples.

While I agree that the objects-as-closure approach is more elegant, it is less common. Most class-like code today is expressed in the prototype/this-based style.

Yes that is true and I think I know why it is less popular.

When a programmers new to ECMAScript want to make a class, they look in JavaScript books for language support for making classes. They find that the language gives them the new/prototype/this machinery. They then struggle mapping their ideas of classes from C++, Java, etc onto the new/prototype/this machinery because they think that in order to be able to do object-oriented programming the language must provide machinery specific to that task. Since the job of these books is to explain the language, it appears that new/prototype/this are the way to do OOP in ECMAScript.

What these programmers don't know is that books like SICP and JavaScript: The Good Parts show that the language has at least one other way to do the whole OOP business.

So new/prototype/this win popularity by default because the books are obligated to spend space explaining them. The new/prototype/this-style isn't winning in the popularity race based on merit in all or perhaps even most cases.

For example, I had a new programmer join my team a several months ago. He expressed skepticism when I said we don't use "new", "prototype", or "this" but he was willing to play along. After a couple months, he told me that he had changed his mind and thought the closure-based system was more natural in JavaScript.

Personally, for new code that does not need to interoperate with old prototype/this-based code and does not need to be super high performance, I will always use the objects-as-closures pattern.

It is the same for me.


Thanks for you're detailed response, Mark.

Peter

# Juan Ignacio Dopazo (14 years ago)

Both styles are equally useful. Prototype based code has its own advantages such as being able to easily modify the behavior of multiple objects on the fly (very useful when working with 3rd party code for instance).

However, it is a lot easier to write concise code for the objects as closures pattern than the prototype based one, specially considering new toys like arrow functions.

let makePoint = (x, y) -> { getDistance: -> Math.sqrt(x * x, y * y) };

We have to agree that prototype based construction is a lot more verbose and could surely use the syntactic sugar.

Also, if you where going to standardize something that's going to be used by developers in lots of situations that you can't predict, you would surely chose the more efficient one (memory-wise in this case), wouldn't you?

Juan

# Allen Wirfs-Brock (14 years ago)

On Jun 3, 2011, at 9:43 PM, Peter Michaux wrote:

... closure-based system ----------------------------------

function makePoint(x, y) { return { getDistance: function() { return Math.sqrt(x * x + y * y); } }; }

The classes strawman is proposing terse syntax to make the new/prototype/this-based system more aesthetic.

harmony:classes

Introducing class syntax will be one of the most monumental changes ever made to ECMAScript and I suggest that unfortunately the proposal is targeting the wrong version of creating constructors. I've found the closure-based system more compelling than the new/prototype/this-based system. My memory even makes me think that this list was heading in the direction of sugaring the closure-based system in 2008.

www.mail-archive.com/[email protected]/msg00335.html

Was using class syntax to sugar the closure-based system thrown out as a possibility for some reason?

Note that the enhanced object literal proposals that were also promoted harmony:object_literals significantly enhance what can be expressed by an object literal used in the closure pattern:

const pointProto = { /* shared methods that don't use closure captured state */}

function makePoint(x, y) { return pointProto <| { getDistance() { //getDistance is a non-enumerable property, like methods should be return Math.sqrt(x * x + y * y); } }; }

# Axel Rauschmayer (14 years ago)

I am also one of those people who like prototypal inheritance and not out of ignorance: I have read my SICP and understand how the closure-based approach works.

Advantages of prototypal inheritance:

  • Sharing data between instances and between types and subtypes.

  • Clear separation of responsibility: The constructor adds instance-specific data, the prototype contains information that is shared between instances.

  • Inheritance: Though clumsy, it can be done. The closure approach would be more complicated here (optional "self" parameter to which properties are added, but then you can’t use object literals, any more). This is where JS prototypal inheritance really needs help, even if it is just something as simple as YUI’s extend().

To truly appreciate the elegance of prototypal inheritance, I recommend the following paper: “Organizing Programs Without Classes”, David Ungar, Craig Chambers, Bay-Wei Chang, and Urs Hölzle. selflanguage.org/documentation/published/organizing-programs.html

The challenge with prototypal inheritance in JavaScript is to get it right. But with a little syntactic sugar that wouldn’t be an issue.

# Peter Michaux (14 years ago)

On Sat, Jun 4, 2011 at 1:59 PM, Axel Rauschmayer <axel at rauschma.de> wrote:

I am also one of those people who like prototypal inheritance and not out of ignorance: I have read my SICP and understand how the closure-based approach works.

No doubt the above can be true and I didn't mean to imply people like the prototypal system only due ignorance. There are definitely cases where the prototype pattern is useful. I haven't found that to be common, however, in the kind of programming I do or read about.

Peter

# Peter Michaux (14 years ago)

On Sat, Jun 4, 2011 at 9:52 AM, Juan Ignacio Dopazo <dopazo.juan at gmail.com> wrote:

Both styles are equally useful. Prototype based code has its own advantages such as being able to easily modify the behavior of multiple objects on the fly (very useful when working with 3rd party code for instance).

Yes but this is a limitation of our tools. If Firebug let you into a closure and edit the code inside the closure, for example, you could have this ability with the closure based system.

However, it is a lot easier to write concise code for the objects as closures pattern than the prototype based one, specially considering new toys like arrow functions. let makePoint = (x, y) -> { getDistance: -> Math.sqrt(x * x, y * y) }; We have to agree that prototype based construction is a lot more verbose and could surely use the syntactic sugar.

Yes that is true. The prototype/new/this business really does scream out for syntactic help. I just think the whole system could be left behind.

Also, if you where going to standardize something that's going to be used by developers in lots of situations that you can't predict, you would surely chose the more efficient one (memory-wise in this case), wouldn't you?

Both are efficient enough for most situations where a scripting language can be used and as Mark mentioned the closure-based system could be optimized more if there was motivation.

Peter

# Peter Michaux (14 years ago)

On Sat, Jun 4, 2011 at 12:24 AM, Mark S. Miller <erights at google.com> wrote:

Btw, I'd like to thank you again for having made the suggestion at esdiscuss/2008-November/008185 for supporting objects-as-closure with a "public" annotated declaration in what was essentially a block body. This suggestion survived through many class strawmen and is now in the promoted proposal.

Thanks but now I'm thinking "I've really gone and done it. In 10 years people are going to be blaming me for that accursed feature." ;-)

Peter

# Brendan Eich (14 years ago)

On Jun 4, 2011, at 3:00 PM, Peter Michaux wrote:

On Sat, Jun 4, 2011 at 9:52 AM, Juan Ignacio Dopazo <dopazo.juan at gmail.com> wrote:

Both styles are equally useful. Prototype based code has its own advantages such as being able to easily modify the behavior of multiple objects on the fly (very useful when working with 3rd party code for instance).

Yes but this is a limitation of our tools. If Firebug let you into a closure and edit the code inside the closure, for example, you could have this ability with the closure based system.

This is hard, though. It's related to the optimization challenges in joining function objects to their one expression form. See

www.mail-archive.com/[email protected]/msg03904.html, www.mail-archive.com/[email protected]/msg03906.html

All solvable, but hard enough that even the latest JS engines (last I checked) show slowdowns when you scale up objects as closures vs. the prototypal equivalent.

I know, it's a vicious cycle. We can't get engine implementors to optimize harder without somehow making closure costs hurt, but since closure costs hurt developers first and engine implementors second or third, while prototypes hurt less, many developers choose prototypes. JS has prototypes as well as closures, and prototypes allow explicit sharing of "methods". This ship sailed long ago.

Good to see class syntax supporting both styles, in any event.

# Kam Kasravi (14 years ago)

Although this ship has sailed, its unfortunate the keyword privileged was never considered as part of the closure pattern and valid syntax within the classes strawman,  where public operated on the prototype chain and privileged operated on the closure.  Now its less clear what type of pattern is being employed since public methods within the constructor are not on the prototype and cannot be extended.

# Christopher M. Balz (14 years ago)

Are there proposals for fixing, without going as far as making a 'class' system, the major drawback of prototype-based inheritance: Without something like a JavaScript (js) class factory (a class factory as provided by most js frameworks) to provide inheriting instances their own copies of mutables (objects, as distinguished from immutables such as strings, numbers, and functions), all inherited mutables are always shared by all inheriting instances, even when modified by a single inheriting instance.  The problem does not exist with immutables, as unique copies are bestowed upon an inheriting instance (as I understand it) if and when it modifies the property.

Also, without going so far as making a 'class' system, are there proposals for fixing these limitations: The confusing 'constructor' property value, the inability of 'this' properties to be private (we can do privates now with a closure, of course, but they are not inherited along the prototype chain), and the limited reflective capabilities of JavaScript.

Regarding the latter, in my development workgroups (engineers using JavaScript in collaborative teams to build Web-based applications), using 'this.$DATATYPE' (obviously, when using a class factory) has been popular as it aids with practical development velocity.  The '$' makes the property name float to the upper segment of the relevant list in the debugger, so the developer can quickly glance to see what kind of object s/he is currently stopped in.  However, I'm asking about a built-in way to do the same thing, and without classes (e.g., 'this.$NAME').

In the JavaScript frameworks I've done and worked on, 'class' has been very practical as almost all developers can easily understand it and it does not surprise them with hard-to-fix bugs related to shared object properties from the prototype chain.  But that fact is due to the dominance of Java and C++ in the scholastic curriculum and industry.  As JavaScript gains the surprising dominance and pervasiveness we see today, perhaps the need for 'class' has diminished now.  Additionally, if I may offer an anecdotal impression, the general JavaScript user community has become quite sophisticated about JavaScript and I hear many developers wanting to stick with plain prototypes, apparently for this aim of simplicity.

Summing up, it seems that adding 'class', while very helpful for the vast majority of developers who have been trained in Java and C++, does stray far from the original intent of simplicity of what I understand to be one of the inspirations for JavaScript, 'Self' (e.g., "Self: The Power of Simplicity", labs.oracle.com/self/papers/self-power.html).   And the center of gravity may have shifted toward JavaScript enough that 'class' may no longer be as needed by the user community as it was even a couple years ago.  So I think it would be better if 'class' could be avoided and instead, the few drawbacks I mention above fixed with some choice keywords (for example, a keyword to mark a mutable (object) property of a prototype instance such that inheriting instances would get their own unique copies of it).  That would enable many or most of the benefits of a 'class' system, while preserving the simplicity of the unity of type and instance that was one of the original selling points of 'Self'.

# Allen Wirfs-Brock (14 years ago)

On Jun 5, 2011, at 7:50 PM, Christopher M. Balz wrote:

Are there proposals for fixing, without going as far as making a 'class' system, the major drawback of prototype-based inheritance: Without something like a JavaScript (js) class factory (a class factory as provided by most js frameworks) to provide inheriting instances their own copies of mutables (objects, as distinguished from immutables such as strings, numbers, and functions), all inherited mutables are always shared by all inheriting instances, even when modified by a single inheriting instance. The problem does not exist with immutables, as unique copies are bestowed upon an inheriting instance (as I understand it) if and when it modifies the property.

... Summing up, it seems that adding 'class', while very helpful for the vast majority of developers who have been trained in Java and C++, does stray far from the original intent of simplicity of what I understand to be one of the inspirations for JavaScript, 'Self' (e.g., "Self: The Power of Simplicity", labs.oracle.com/self/papers/self-power.html). And the center of gravity may have shifted toward JavaScript enough that 'class' may no longer be as needed by the user community as it was even a couple years ago. So I think it would be better if 'class' could be avoided and instead, the few drawbacks I mention above fixed with some choice keywords (for example, a keyword to mark a mutable (object) property of a prototype instance such that inheriting instances would get their own unique copies of it). That would enable many or most of the benefits of a 'class' system, while preserving the simplicity of the unity of type and instance that was one of the original selling points of 'Self'.

In self, this problem seems to be address by the object creation convention. New objects are created by invoking the "copy" method on the intended prototype object. Every such object is expected to define an appropriate copy method that takes care of copying non-sharable mutable state. In JavaScript terms:

Object.prototype.copy = function () {return Object.create(this)};

var Polygon = { vertices: [{x:0,y:0}, {x:1,y:0}, {x:1,y:1}], //default is a unit right triangle copy: function() { var newPoly = super.copy(); //proposed for ES.next, in ES 3/5 say: Object.prototype.copy.call(this) newPoly = this.vertices.copy(); } }

var mySquare = Polygon.copy(); mySquare.vertices[3]={x:0,y:1};

# Allen Wirfs-Brock (14 years ago)

(correction copy function below)

# Allen Wirfs-Brock (14 years ago)

and another... On Jun 6, 2011, at 11:44 AM, Allen Wirfs-Brock wrote:

(correction copy function below) On Jun 6, 2011, at 10:58 AM, Allen Wirfs-Brock wrote:

On Jun 5, 2011, at 7:50 PM, Christopher M. Balz wrote:

Are there proposals for fixing, without going as far as making a 'class' system, the major drawback of prototype-based inheritance: Without something like a JavaScript (js) class factory (a class factory as provided by most js frameworks) to provide inheriting instances their own copies of mutables (objects, as distinguished from immutables such as strings, numbers, and functions), all inherited mutables are always shared by all inheriting instances, even when modified by a single inheriting instance. The problem does not exist with immutables, as unique copies are bestowed upon an inheriting instance (as I understand it) if and when it modifies the property.

... Summing up, it seems that adding 'class', while very helpful for the vast majority of developers who have been trained in Java and C++, does stray far from the original intent of simplicity of what I understand to be one of the inspirations for JavaScript, 'Self' (e.g., "Self: The Power of Simplicity", labs.oracle.com/self/papers/self-power.html). And the center of gravity may have shifted toward JavaScript enough that 'class' may no longer be as needed by the user community as it was even a couple years ago. So I think it would be better if 'class' could be avoided and instead, the few drawbacks I mention above fixed with some choice keywords (for example, a keyword to mark a mutable (object) property of a prototype instance such that inheriting instances would get their own unique copies of it). That would enable many or most of the benefits of a 'class' system, while preserving the simplicity of the unity of type and instance that was one of the original selling points of 'Self'.

In self, this problem seems to be address by the object creation convention. New objects are created by invoking the "copy" method on the intended prototype object. Every such object is expected to define an appropriate copy method that takes care of copying non-sharable mutable state. In JavaScript terms:

Object.prototype.copy = function () {return Object.create(this)};

var Polygon = { vertices: [{x:0,y:0}, {x:1,y:0}, {x:1,y:1}], //default is a unit right triangle copy: function() { var newPoly = super.copy(); //proposed for ES.next, in ES 3/5 say: Object.prototype.copy.call(this) newPoly.vertices = this.vertices.copy(); return newPoly;

# Christopher M. Balz (14 years ago)

Thanks Allen.  The new 'Object.create' functionality you bring up is certainly important to this discussion.  It still leaves inheritance mechanics such that they must be performed imperatively, instead of specified declaratively.  I think that we can dispense with such arrangements, with JavaScript framework class engines, and not least with actual native 'class' syntax by basically just adding a declarative annotation such as 'nonshared' in front of mutable 'this' properties of objects.

For example, instead of this current situation (note the undesirably shared mileage in the example below):

oAuto = {         oEngine : { iMiles : 0 }     };

oCar = Object.create( oAuto );

oMyCar = Object.create( oCar );     oMyOtherCar = Object.create( oMyOtherCar );

oMyCar.oEngine.iMiles         0     oMyCar.oEngine.iMiles = 10000;     oMyCar.oEngine.iMiles     10000     oMyOtherCar.oEngine.iMiles     10000

- we could instead keep to a pure prototype-based inheritance model but not have the above issue of undesired sharing by doing something declarative as in the example code below that uses a 'nonshared' annotation:

oAuto = {         @nonshared oEngine : { iMiles : 0 }     };

oCar = Object.create( oAuto );

oMyCar = Object.create( oCar );     oMyOtherCar = Object.create( oMyOtherCar );

oMyCar.oEngine.iMiles     0     oMyCar.oEngine.iMiles = 10000;     oMyCar.oEngine.iMiles     10000     oMyOtherCar.oEngine.iMiles     0

This keeps JavaScript "simple" but adds the one major feature not currently supported by prototypes, unique copies of inherited objects.  Also, it greatly extends the utility of 'Object.create' by avoiding the current necessity to use imperative code to get desired inheritance results.

As I mentioned above in an earlier post in this thread, inadvertent sharing due to misplaced imperative commands, and even the need to do that kind of housekeeping work, has been seen to warrant class syntax (both native and JavaScript-framework supported).  But class syntax then requires "fixing" the constructor property, possibly adding the superclass call to every constructor, and in general, supporting a construct that seems less and less in demand in the developer (JavaScript user) community.

# Allen Wirfs-Brock (14 years ago)

On Jun 16, 2011, at 8:34 PM, Christopher M. Balz wrote:

Thanks Allen. The new 'Object.create' functionality you bring up is certainly important to this discussion. It still leaves inheritance mechanics such that they must be performed imperatively, instead of specified declaratively. I think that we can dispense with such arrangements, with JavaScript framework class engines, and not least with actual native 'class' syntax by basically just adding a declarative annotation such as 'nonshared' in front of mutable 'this' properties of objects.

For example, instead of this current situation (note the undesirably shared mileage in the example below):

oAuto = {
    oEngine : { iMiles : 0 }
};

oCar = Object.create( oAuto );

oMyCar = Object.create( oCar );
oMyOtherCar = Object.create( oMyOtherCar );

do you mean: oMyOtherCar = Object.create(oChar); or perhaps: oMyOtherCar = Object.create(oMyChar)

oMyCar.oEngine.iMiles    
0
oMyCar.oEngine.iMiles = 10000;
oMyCar.oEngine.iMiles
10000
oMyOtherCar.oEngine.iMiles
10000
  • we could instead keep to a pure prototype-based inheritance model but not have the above issue of undesired sharing by doing something declarative as in the example code below that uses a 'nonshared' annotation:

    oAuto = { @nonshared oEngine : { iMiles : 0 }

Yes, but what is the non-shared semantics. It presumably creates a own property in a derived object but how is that property initialized. Is some sort of copy performed on the current value of the original property. Or is the the original initialization code for the property re-evaluted to initialize the new own property. What if some sort of invariant needs to be maintained among the values of multiple properties.

All these issues are presumably why self delegates the "copy" semantics for creating a new instance derived from a prototype to the prototype. Only the prototype knows how to initialize non-shared state that is derived from it. It is easy to make new property slots. It's hard to know what values to place in them.

This is really the same as a subclass constructor need to call the superclass constructor. It is the superclass that knows how to initialize the instance variables it provides to the subclass

};

oCar = Object.create( oAuto );

oMyCar = Object.create( oCar );
oMyOtherCar = Object.create( oMyOtherCar );

oMyCar.oEngine.iMiles
0
oMyCar.oEngine.iMiles = 10000;
oMyCar.oEngine.iMiles
10000
oMyOtherCar.oEngine.iMiles
0

This keeps JavaScript "simple" but adds the one major feature not currently supported by prototypes, unique copies of inherited objects. Also, it greatly extends the utility of 'Object.create' by avoiding the current necessity to use imperative code to get desired inheritance results.

As I mentioned above in an earlier post in this thread, inadvertent sharing due to misplaced imperative commands, and even the need to do that kind of housekeeping work, has been seen to warrant class syntax (both native and JavaScript-framework supported). But class syntax then requires "fixing" the constructor property, possibly adding the superclass call to every constructor, and in general, supporting a construct that seems less and less in demand in the developer (JavaScript user) community.

I think the imperative initialization is always going to be necessary. You can declarative identify which property need to be replicated but initializing them takes imperative code. This is the case whether your mechanism is prototypal inheritance or class inheritance.

BTW, for another take on how we might emphasize prototypes rather than classes see my recent "Prototypes as the new class declaration" post.

# Christopher M. Balz (14 years ago)

do you mean:  oMyOtherCar = Object.create(oChar);  or perhaps: oMyOtherCar = Object.create(oMyChar)

Per Allen's question, yes, typo on my part - I meant:

oMyOtherCar = Object.create( oCar );

So, both 'oMyOtherCar' and 'oMyCar' are created from the same prototype.

Yes, but what is the non-shared semantics.  It presumably creates a own property in a derived object but how is that property initialized.

That's what my suggestion intends.  It would be either a deep copy made at creation time, or alternatively would work like immutables inherited from the prototype chain apparently do now: The unique (and deep) copy would only be made in an inheriting object if a property of the non-shared mutable were changed.

Only the prototype knows how to initialize non-shared state that is derived from it.

This would be a declarative way to streamline that process, which, granted, would not be as flexible since it cannot take parameters from an inheriting object.  The values copied into the inheriting object would be simply what exist in the provided prototype object - in this case, the property 'oEngine'.

What if some sort of invariant needs to be maintained among the values of multiple properties.

I'm not sure why maintaining an invariant would be hard in this case.  If you mean a constant or final value, I would think that characteristic would be carried along in the copy operation.  Sorry if I'm missing something there.

It is the superclass that  knows how to initialize the instance variables it provides to the subclass

In this example, the prototype could have a 'drive' method that would increment the 'iMiles' property on 'oEngine'.  But 'drive' isn't an initialization method; it's run-time.  Certainly, imperative code (such as in an 'init' method or in class semantics, a 'constructor') could be used to perform init-time modifications.  But making non-shared mutable (e.g., object) properties should be easier than remembering to do that all the time non-shared object properties are needed, especially because there are many cases such as the car mileage example where no special initialization is required (miles are set to zero on construction).

Mainly though, making it easy to mark a mutable as non-shared removes, at least as I see it, a major pitfall for JavaScript users where they create mutables in inheritance hierarchies without realizing that they are shared amongst inheriting instances.  Even if the developer (JavaScript user) knows that mutables are shared by default, it's easy to forget to make a 'constructor' or 'init' method to stamp out unique copies and then to be sure to invoke that in subclasses/inheriting objects.  A failure on either end results in a bad bug.

All these issues are presumably why self delegates the "copy" semantics for creating a new instance derived from a prototype to the prototype.

Thanks for pointing that out in your earlier post in this thread.  Your recent "Prototypes as the new class declaration" post looks great.  Although I don't yet understand the entirety of it - for example, why use 'constructor' instead of 'copy' if the focus is to be prototypes instead of classes?  But possibly the other thread would be the place for that question.