Look Ma, no "this" (was: ECMAScript Harmony)

# Mark S. Miller (16 years ago)

On Wed, Aug 13, 2008 at 7:15 PM, Peter Michaux <petermichaux at gmail.com> wrote:

On Wed, Aug 13, 2008 at 2:26 PM, Brendan Eich <brendan at mozilla.org> wrote:

[snip]

We talked about desugaring classes in some detail in Oslo. During these exchanges, we discussed several separable issues, including classes, inheritance, like patterns, and type annotations. I'll avoid writing more here,

Is there more to read elsewhere? I'd like to know concretely what "desugaring classes" means.

The main difference from the old "Classes as Sugar" proposal is to desugar to the objects-as-closure style pioneered by Crock rather than ES3-classical style of prototypical inheritance + this-binding.

Point as a final root class:

function Point(x, y) { const self = Object.create(Point.prototype, { toString: {value: Object.freeze(function() ('<' + self.getX()

  • ',' + self.getY() + '>'))}, enumerable: true}, getX: {value: Object.freeze(function() x), enumerable: true}, getY: {value: Object.freeze(function() y), enumerable: true} }, true); return self; }

(Assuming that absent attributes default to false, which I don't think is currently the case in the ES3.1 draft.)

If we stick with zero inheritance, which seemed attractive at Oslo, we can skip the part about inheritance below. Otherwise, read on.

<inheritance>

Point as a non-final non-abstract root/mixin class where toString is a final method:

function PointMixin(self, x, y) { Object.defineProperties(self, { toString: {value: Object.freeze(function() ('<' + self.getX()

  • ',' + self.getY() + '>'))}, enumerable: true}, getX: {value: Object.freeze(function() x), enumerable: true, flexible: true}, getY: {value: Object.freeze(function() y), enumerable: true, flexible: true} }); } function Point(x, y) { const self = Object.create(Point.prototype); // only for instanceof PointMixin(self, x, y); return Object.freeze(self); } Object.freeze(PointMixin); Object.freeze(Point.prototype); Object.freeze(Point);

WobblyPoint as a non-abstract non-final subclass:

function WobblyPointMixin(self, wobble) { const super = Object.snapshot(self); // a snapshot is a frozen copy Object.defineProperties(self, { getX: {value: function() (super.getX() + Math.random()*wobble), enumerable: true, flexible: true} }); } function WobblyPoint(x, y, wobble) { const self = Object.create(WobblyPoint.prototype); // only for instanceof PointMixin(self, x, y); WobblyPointMixin(self, wobble); return Object.freeze(self); } Object.freeze(WobblyPointMixin); WobblyPoint.prototype = Object.create(Point.prototype, { constructor: {value: WobblyPoint} }, true); Object.freeze(WobblyPoint);

This gets self-overriding a super-binding correct under single inheritance and even under linearized multiple inheritance.

</inheritance>

Further, methods auto-bind on extraction, as they did in ES4:

const pt = new WobblyPoint(3, 4, 0.1); const gx = pt.getX;

gx is a no argument function bound to pt. For ES3-style classical code, you'd instead have to say "pt.getX.bind(pt)".

Notice that the above code works well because it never says "this". JavaScript's "this" is an incredibly tricky construct. However, the above technique is impractical today because of the extra allocation cost -- one closure per method per instance. But as Dan Ingalls says "you can cheat if you don't get caught." The above desugaring shows how to define the semantics of the class construct. The actual behavior of the class construct must not be observably different from some such desugaring. But in a class-aware implementation, it should of course perform better than you'd expect from this desugaring.

In the Caja project, we are exploring whether this optimization can even be provided as a source-to-source translation: google-caja.googlecode.com/svn/trunk/doc/html/cajitaOptimization/index.html.

It's not yet clear that the idea is practically implementable by this technique groups.google.com/group/google-caja-discuss/browse_thread/thread/df6c8ea9a1ca1aa3.

But none of these problems should impede a more directly implemented optimization.

# Michael Daumling (16 years ago)

Just a side note: The code below would create three Function objects per Point instance. Some may argue that the days of having little memory are long gone, but we still have small devices plus a garbage collector that may need to iterate through live objects, including three Function objects per Point. Long live prototype objects.

Michael

# Mark S. Miller (16 years ago)

On Tue, Aug 19, 2008 at 5:54 PM, Michael Daumling <mdaeumli at adobe.com> wrote:

Just a side note: The code below would create three Function objects per Point instance. Some may argue that the days of having little memory are long gone, but we still have small devices plus a garbage collector that may need to iterate through live objects, including three Function objects per Point. Long live prototype objects.

Michael, I think you missed the note at the end of the message you're quoting:

# Michael Daumling (16 years ago)

I sure did. Sorry for the noise.

Michael

# Allen Wirfs-Brock (16 years ago)

I thought it was Peter Deutsch who originally said "you can cheat if you don't get caught." regarding Smalltalk implementations

# Dean Edwards (16 years ago)

Mark S. Miller wrote:

<inheritance>

Point as a non-final non-abstract root/mixin class where toString is a final method:

function PointMixin(self, x, y) { Object.defineProperties(self, { toString: {value: Object.freeze(function() ('<' + self.getX()

  • ',' + self.getY() + '>'))}, enumerable: true}, getX: {value: Object.freeze(function() x), enumerable: true, flexible: true}, getY: {value: Object.freeze(function() y), enumerable: true, flexible: true} }); } function Point(x, y) { const self = Object.create(Point.prototype); // only for instanceof PointMixin(self, x, y); return Object.freeze(self); } Object.freeze(PointMixin); Object.freeze(Point.prototype); Object.freeze(Point);

WobblyPoint as a non-abstract non-final subclass:

function WobblyPointMixin(self, wobble) { const super = Object.snapshot(self); // a snapshot is a frozen copy Object.defineProperties(self, { getX: {value: function() (super.getX() + Math.random()*wobble), enumerable: true, flexible: true} }); } function WobblyPoint(x, y, wobble) { const self = Object.create(WobblyPoint.prototype); // only for instanceof PointMixin(self, x, y); WobblyPointMixin(self, wobble); return Object.freeze(self); } Object.freeze(WobblyPointMixin); WobblyPoint.prototype = Object.create(Point.prototype, { constructor: {value: WobblyPoint} }, true); Object.freeze(WobblyPoint);

This gets self-overriding a super-binding correct under single inheritance and even under linearized multiple inheritance.

</inheritance>

That code is ugly.

# Mark S. Miller (16 years ago)

On Tue, Aug 19, 2008 at 6:47 PM, Dean Edwards <dean at edwards.name> wrote:

That code is ugly.

Yes indeed. That's why everyone agrees that this pattern needs some syntactic sugar.

# Kris Zyp (16 years ago)

function Point(x, y) { const self = Object.create(Point.prototype, { toString: {value: Object.freeze(function() ('<' + self.getX()

  • ',' + self.getY() + '>'))}, enumerable: true}, getX: {value: Object.freeze(function() x), enumerable: true}, getY: {value: Object.freeze(function() y), enumerable: true} }, true); return self;

Why do you freeze the functions? Is this just to cater to mutable function critics, or is there actually a reason tied class semantics?

Kris

# David-Sarah Hopwood (16 years ago)

Allen Wirfs-Brock wrote:

I thought it was Peter Deutsch who originally said "you can cheat if you don't get caught." regarding Smalltalk implementations

I think the source of the attribution to Ingalls is this paper:

The Smalltalk-76 Programming System - Design and Implementation Daniel H. H. Ingalls users.ipa.net/~dwighth/smalltalk/St76/Smalltalk76ProgrammingSystem.html

Efficient Message Handling

It should be obvious that to carry the message sending metaphor down into

integer arithmetic will result in a slow system on any non message

oriented computer. The implementor must cheat, but not get caught. In

other words, the user of the system should not perceive any

non-uniformity.

It is possible that Deutsch said it earlier, of course.

# Mark S. Miller (16 years ago)

On Tue, Aug 19, 2008 at 9:15 PM, Kris Zyp <kris at sitepen.com> wrote:

Why do you freeze the functions? Is this just to cater to mutable function critics, or is there actually a reason tied class semantics?

It is to cater to mutable function critics, since they're right ;).

# Kris Zyp (16 years ago)

I don't see why it is better to have classes be sugar for closured object literals rather than prototype based structures. It seems the benefits that are being sought after are auto-binding on method extraction and private method creation. Both of these can be attained with prototype-based class desugaring. If you really you want auto-binding on method extraction (which IMO is of very minimal value), why not do it this way and keep class semantics much closer to the prototype techniques used in JavaScript today:

(function(){ // desugared Point class Point = function(){}; function privateMethod(){ } Point.prototype = { get getX(){ return function(){ return this.x; }.bind(this); }, get getY(){ ... } get publicMethod(){ // example public method calling an example private method return function(){ // sugared version would be this.privateMethod(1,2) privateMethod.apply(this,1,2); }.bind(this); } } });

However, I would prefer |this| instanceof checking instead auto-binding on extraction. Rather than binding on extraction, class methods would always have an implicit check to make sure they were called with an object that was an instance of (instanceof) the class: Point = function(){}; Point.prototype = { getX : function(){ if (!(this instanceof Point)){ throw new TypeError("Method called with incompatible object instance"); } return this.x; }, ... };

By using type checking instead of binding on extraction, this would allow functions that recieve a function/method as parameter to apply the function to appropriate compatible object instance with apply or call: function showCoordinateOnSelect(coordinateGetter){ table.onclick = function(event){ var point = getPointForClick(event); alert(coordinateGetter.call(point)); } } ... showCoordinateOnSelect(Point.prototype.getX);

By using prototype based semantics for future class sugar, we can retain the same semantics used by vast numbers of JavaScript libraries and programmers themselves. VMs can just as easily apply clever optimizations for these structures, and existing class constructs will have a smooth migration to sugared syntax.

Thanks, Kris

On Tue, Aug 19, 2008 at 9:15 PM, Kris Zyp <kris at sitepen.com> wrote:

Why do you freeze the functions? Is this just to cater to mutable function critics, or is there actually a reason tied class semantics?

It is to cater to mutable function critics, since they're right ;).

That may be, but it seems like an orthogonal feature, seems like it should be discussed separately to avoid confusing the goal of basic class desugaring.

Thanks, Kris

----- Original Message ---

# Mark S. Miller (16 years ago)

On Sun, Aug 24, 2008 at 3:22 PM, Kris Zyp <kris at sitepen.com> wrote:

I don't see why it is better to have classes be sugar for closured object literals rather than prototype based structures. It seems the benefits that are being sought after are auto-binding on method extraction and private method creation.

I'm not sure what you mean by "private method creation", so I'm not sure whether you've covered the other main motivation: encapsulated instance variables. ES3 has only one encapsulation mechanism: lexical capture by closures. ES4 achieved class-private instance variables by use of namespaces. My earlier Classes-as-Sugar proposal suggested using the prototype chain much as you do here, and adding another property attribute to mark a property as "private". This gives instance-private rather than class-private variables, which is the safer default for a dynamic language. The new objects-as-closure sugar also gives instance-private encapsulation, and without proposing any new semantic state. I think it is better in all ways.

Both of these can be attained with prototype-based class desugaring. If you really you want auto-binding on method extraction (which IMO is of very minimal value), why not do it this way and keep class semantics much closer to the prototype techniques used in JavaScript today:

(function(){ // desugared Point class Point = function(){}; function privateMethod(){ }

I don't understand the point you're making with privateMethod. How do you provide encapsulated per-instance state?

However, I would prefer |this| instanceof checking instead auto-binding on extraction. Rather than binding on extraction, class methods would always have an implicit check to make sure they were called with an object that was an instance of (instanceof) the class:

In the absence of inheritance, I suppose this is safe. But it is not safe when combined with inheritance. If b is an instance of B which extends A, and B overrides A.foo(), then the author of B should be able to assume that no one outside b can call A.foo() on b. Your proposal would still allow an attacker to A.foo.call(b), which might violate b's integrity.

By using type checking instead of binding on extraction, this would allow functions that recieve a function/method as parameter to apply the function to appropriate compatible object instance with apply or call: function showCoordinateOnSelect(coordinateGetter){ table.onclick = function(event){ var point = getPointForClick(event); alert(coordinateGetter.call(point)); } } ... showCoordinateOnSelect(Point.prototype.getX);

Just use a normal function instead of a method.

It is to cater to mutable function critics, since they're right ;).

That may be, but it seems like an orthogonal feature, seems like it should be discussed separately to avoid confusing the goal of basic class desugaring.

It's actually not orthogonal. We freeze methods by default for the same reason that we freeze the object by default: so that clients of an instance of a class, by default, can only interact with each other by virtue of sharing that instance according to the behavior explicitly provided by that instance.

But it is sufficiently separate that it can be discussed separately.

# Kris Zyp (16 years ago)

I don't see why it is better to have classes be sugar for closured object literals rather than prototype based structures. It seems the benefits that are being sought after are auto-binding on method extraction and private method creation.

I'm not sure what you mean by "private method creation", so I'm not sure whether you've covered the other main motivation: encapsulated instance variables.

I did not, good to know that that is the motivation.

ES3 has only one encapsulation mechanism: lexical capture by closures. ES4 achieved class-private instance variables by use of namespaces. My earlier Classes-as-Sugar proposal suggested using the prototype chain much as you do here, and adding another property attribute to mark a property as "private". This gives instance-private rather than class-private variables, which is the safer default for a dynamic language. The new objects-as-closure sugar also gives instance-private encapsulation, and without proposing any new semantic state. I think it is better in all ways.

I am curious how you make that judgement. Creating classes using a structure that is fundamentally different than how inheritance/"classes" are predominantly done on the web today seems like an enormous drawback, and I don't see how avoiding the addition of a new semantic state is so valuable as to overcome this drawback. What is so dreadful about adding a "private" attribute that necessitates these class semantics based on different inheritance techniques? If the only barrier is for someone to do a desugaring exercise with the prototype based construction using existing semantics, I believe it is still possible to emulate private instance variables with prototypes (although much more awkward than with a "private" attribute). I could demonstrate if desired.

Both of these can be attained with prototype-based class desugaring. If you really you want auto-binding on method extraction (which IMO is of very minimal value), why not do it this way and keep class semantics much closer to the prototype techniques used in JavaScript today:

(function(){ // desugared Point class Point = function(){}; function privateMethod(){ }

I don't understand the point you're making with privateMethod. How do you provide encapsulated per-instance state?

However, I would prefer |this| instanceof checking instead auto-binding on extraction. Rather than binding on extraction, class methods would always have an implicit check to make sure they were called with an object that was an instance of (instanceof) the class:

In the absence of inheritance, I suppose this is safe. But it is not safe when combined with inheritance. If b is an instance of B which extends A, and B overrides A.foo(), then the author of B should be able to assume that no one outside b can call A.foo() on b. Your proposal would still allow an attacker to A.foo.call(b), which might violate b's integrity.

It is only an integrity violation if you assume that the author of B assumes that no one will call A.foo() on b. If there is no guarantees of preventing the A.foo() call, than the author of B just can't make any such reliances on such a mechanism. Alternately, if people really felt that preventing A.foo() calls was so important (I don't), you could use a stricter type checking mechanism that ensured that the method being called was the unshadowed method in the prototype chain.

By using type checking instead of binding on extraction, this would allow functions that recieve a function/method as parameter to apply the function to appropriate compatible object instance with apply or call: function showCoordinateOnSelect(coordinateGetter){ table.onclick = function(event){ var point = getPointForClick(event); alert(coordinateGetter.call(point)); } } ... showCoordinateOnSelect(Point.prototype.getX);

Just use a normal function instead of a method.

I am not sure I understand, are you suggesting that programmers should not be able to pass around a method?

Thanks, Kris

# Mark S. Miller (16 years ago)

On Sun, Aug 24, 2008 at 5:10 PM, Kris Zyp <kris at sitepen.com> wrote:

[...] I believe it is still possible to emulate private instance variables with prototypes (although much more awkward than with a "private" attribute). I could demonstrate if desired.

I desire. Please do. Thanks.

# Brendan Eich (16 years ago)

On Aug 24, 2008, at 4:09 PM, Mark S. Miller wrote:

This gives instance-private rather than class-private variables, which is the safer default for a dynamic language. The new objects-as-closure sugar also gives instance-private encapsulation, and without proposing any new semantic state. I think it is better in all ways.

This is not settled in committee. Instance-private as in Smalltalk
requires writing getters and setters, and at least some kind of
branding or sealer/unsealer pair test so that Point methods can even
tell they're dealing with another Point instance.

Many more conventional and nearby languages support class-private
variables, where Point methods could see any instance's privates, not
just its own.

We need to sort this out, but no rush. Your position may not be clear
to the list, though, so I thought I'd elaborate slightly. The
consequence of using lexical scope for private variables is that they
are instance-private. It's a nice hat trick: privacy, higher
integrity, and semantic reuse all in one.

I'm still open to it, but we have the generative Name idea as an
alternative way to make private names, which could be class-private
or even "friend" among classes in the same lexical scope.

Others on this list should comment on class-private vs. instance- private.

# Peter Michaux (16 years ago)

On Sun, Aug 24, 2008 at 6:05 PM, Brendan Eich <brendan at mozilla.org> wrote:

On Aug 24, 2008, at 4:09 PM, Mark S. Miller wrote:

[snip]

Others on this list should comment on class-private vs. instance- private.

If this is just a poll then I'm all for instance-private.

Peter

# Brendan Eich (16 years ago)

Polls are not so good, compared to reasons. Could you give your
rationale and talk about the trade-offs, in your experience?

# Peter Michaux (16 years ago)

[order restored]

On Sun, Aug 24, 2008 at 7:41 PM, Brendan Eich <brendan at mozilla.org> wrote:

On Aug 24, 2008, at 7:36 PM, Peter Michaux wrote:

On Sun, Aug 24, 2008 at 6:05 PM, Brendan Eich <brendan at mozilla.org> wrote:

On Aug 24, 2008, at 4:09 PM, Mark S. Miller wrote:

[snip]

Others on this list should comment on class-private vs. instance- private.

If this is just a poll then I'm all for instance-private.

Polls are not so good, compared to reasons. Could you give your rationale and talk about the trade-offs, in your experience?

You summed it up nicely with the hat trick:

"It's a nice hat trick: privacy, higher integrity, and semantic reuse all in one."

I'm not sure there will be anyone who can explain that any one OOP system is right and the others are less right. That is what I imagine will make consensus on this topic very difficult.. Every OOP language has a different set of OOP features so there doesn't appear to be an objective (ha!) winner after decades of programmers exploring OOP. The fact that this is really a subjective issue is why your initial request for comments seemed somewhat appropriate for a poll. It is a "what do you like" question.

Some folks like all the bells and whistles for easy code reuse (e.g. inheritance and template pattern) and controlling various levels of privacy (e.g. public, protected, private, friends, enemies).

I always seem to end up on the side of keeping things simple (which perhaps aligns well with security issues appropriate to the web and the initial ease of use JavaScript was designed to have.) To me instance-private and zero inheritance are simple. It is easy to read code written this way. Instance-private and zero inheritance makes it easy to reason about how instance state can be changed. There is no hunting up and down the inheritance tree to figure out which ancestor is changing which property of some desendent class instance. That is a real pain. There is no wondering if another instance of the same class is bypassing a setter method it should be using because of class-private variables.

I've been using the closure-based OOP style with zero inheritance the last while (~4 or so months) and it has been a large sigh of relief compared with trying to make prototype-based inheritance have private variables and "super". This style is approximately what seems to have been discussed as the desugared version of classes. I haven't encountered any downsides that are problematic to me or that I'm not willing to pay in the set of trade-offs. I haven't needed class-private perhaps because I just don't think that way or it isn't very useful. I have used languages where class-private is available and didn't use it there either.

While I'm at it the keyboard typing, one thing I really like about the closure-based OOP is it is not based on message passing (at least I would say it isn't the traditional style of message passing because there doesn't need to be a receiver). The constructor returns an object which is a hash of closures, none of which use "this". Each of these closures can be assigned to another variable or another object and that other object cannot access the private variables of the first object. This is good in a language where it is possible to "borrow" any function from any object and still not have to worry about "this". An elegant example is the observer pattern. Here is a bit of silly but small example off the top of my head but shows the idea and benefit.

var makeSubject = function() { var listeners = []; return { subscribe: function(){}, unsubscribe:function(){}, fire: function(){} }; };

var makeDailyEvent = function() { var s = makeSubject(); setInterval(s.fire(), 246060*1000); return { subscribe: s.subscribe, unsubscribe: s.unsubscribe }; };

Because the closures of a Subject object can be borrowed directly there is no need to write the trivial but possibly many wrapper methods for manual delegation in a Java class where "has a" (as opposed to "is a") has been used. So the zero-inheritance issue is not as big an issue in JavaScript. The fact that the "listeners" instance-private array does not become instance-private to the DailyEvent object when the Subject methods are borrowed means I know the "listeners" array is very private.

I've talked about both privacy and inheritance when you only requested about privacy but the two issues are closely related.

Peter

# Peter Michaux (16 years ago)

On Sun, Aug 24, 2008 at 8:40 PM, Peter Michaux <petermichaux at gmail.com> wrote:

setInterval(s.fire(), 246060*1000);

minus the parens after "fire"

Peter

# Garrett Smith (16 years ago)

On Sun, Aug 24, 2008 at 7:41 PM, Brendan Eich <brendan at mozilla.org> wrote:

On Aug 24, 2008, at 7:36 PM, Peter Michaux wrote:

On Sun, Aug 24, 2008 at 6:05 PM, Brendan Eich <brendan at mozilla.org> wrote:

On Aug 24, 2008, at 4:09 PM, Mark S. Miller wrote:

[snip]

Others on this list should comment on class-private vs. instance- private.

If this is just a poll then I'm all for instance-private.

(order restored)

Polls are not so good, compared to reasons. Could you give your rationale and talk about the trade-offs, in your experience?

I'm not Peter, but here are my observations:

How to make a private variable?

Option 1: "Fake Private" - uses _someVar, and even uses JSDocToolkit @private or @internal.

Pros: Refactoring that introduces "private" instance variables won't require changing to "Power Constructor" or other closure-based approach. Cons: Fake.

Example: developer.yahoo.com/yui/docs/menu.js.html

_nCurrentMouseX: 0 is the default in Menu.prototype. In _onMouseOver, the value is set on the instance. It is as if the desire is to inherit the privateness, it is almost as if they wanted [CanPut] to be true only in the Menu code in that js file.

Option 2: Closures. Wrap everything in a closure and have the "private" variables not accessible from the outside. This includes the Module Pattern, Power Constructor (Putting everything in the constructor), and Exporting Pattern approaches.

Closure Pros:

  • Can use shortened lookup chains for "local" variables in the closure.
  • Can minify the "private" variables using a compressor.

Closure Cons:

  • Private instance variables don't fit into the typical constructor-function-with-a-prototype idiom.

Power Constructor cons:

  • Long constructor
  • increases the scope chain of each instance method, which then has reference to things it might not want or need (all variables remain in scope).

Module Pattern cons:

  • increases the scope chain of each instance method, which then has reference to things it might not want or need (all variables remain in scope).
  • "private" variables are not easily distinguished from "local shortcut" variables.

The Exporting Pattern is used to export some methods in a closure to properties of another object, keeping some "private" variables/functions.

Exporting Pattern cons:

  • can lead to "God Object" or "Big Ball of Mud"
  • can be difficult to read/understand

Garrett

# Kris Zyp (16 years ago)

On Sun, Aug 24, 2008 at 5:10 PM, Kris Zyp <kris at sitepen.com> wrote:

[...] I believe it is still possible to emulate private instance variables with prototypes (although much more awkward than with a "private" attribute). I could demonstrate if desired.

I desire. Please do. Thanks.

Does this count? It is ugly and grossly inefficient (even disables GC) without optimization, but I think it provides private instance variables with existing semantics (still not sure why that is really that important):

(function(){ // <boilerplate> var privates = []; var instances = []; function getPrivate(self){ // look for the private object for(var i = 0; i < instances.length; i++){ if(instances[i] === self){ // found it return privates[i]; } } // not found, need to create one on first access instances.push(self); var thisPrivate = {}; privates.push(thisPrivate); return thisPrivate; } // </boilerplate> Point = function(){ typeCheck(this); // implicit type check getPrivate(this).x = Math.random(); }; Point.prototype = { getX : function(){ typeCheck(this); return getPrivate(this).x; }, ... }; })();

Desugared from: class Point { private var x = Math.random(); function getX(){ return this.x; } ... }

Others on this list should comment on class-private vs. instance- private.

I am surprised this is up for debate, I would also think that we would want instance-private by default. Kris

# Brendan Eich (16 years ago)

On Aug 24, 2008, at 8:40 PM, Peter Michaux wrote:

Polls are not so good, compared to reasons. Could you give your
rationale and talk about the trade-offs, in your experience?

You summed it up nicely with the hat trick:

"It's a nice hat trick: privacy, higher integrity, and semantic reuse all in one."

I'm not sure there will be anyone who can explain that any one OOP system is right and the others are less right. That is what I imagine will make consensus on this topic very difficult.. Every OOP language has a different set of OOP features so there doesn't appear to be an objective (ha!) winner after decades of programmers exploring OOP. The fact that this is really a subjective issue is why your initial request for comments seemed somewhat appropriate for a poll. It is a "what do you like" question.

And yet you go on to make a great non-aesthetic case, with particular
and pointed reasoning. (The delegation boilerplate for Java "has-a"
cases scores!) Thanks. I'm still inclined the same way as you and
Mark (and I believe Waldemar, at least at Oslo). IP+ZI FTW! ;-)

I've talked about both privacy and inheritance when you only requested about privacy but the two issues are closely related.

Indeed. Thanks again for the thoughtful response,

# Brendan Eich (16 years ago)

On Aug 24, 2008, at 9:44 PM, Kris Zyp wrote:

I am surprised this is up for debate, I would also think that we
would want instance-private by default.

We can debate lots of things, some that might actually be in play.
AFAIK this one is not decided in the committee (it's way too early),
but IP does have some strong proponents.

AS3, JScript.NET, and Waldemar's original ES4/JS2 work all had CP.
Java has CP. So do C++ and C#. It should not come as a surprise,
therefore, if CP has at least to be dealt with by some rationale for
IP over against CP. "Smalltalk rules" won't cut it ;-).

I'm happy to have a little debate on this topic, given the different
precedents. I'm wondering why you think there's no question.

# Peter Michaux (16 years ago)

On Sun, Aug 24, 2008 at 9:44 PM, Kris Zyp <kris at sitepen.com> wrote:

Desugared from:

class Point { private var x = Math.random(); function getX(){ return this.x; } ... }

Is there any need for the "this."? Some languages allow "this.x" to get out from under the shadow of a local "x" inside "getX". I don't think it is necessary to be able to escape such shadowing and actually increases confusion. If a method is many lines long then the reader may forget that "x" is local and not the instance variable. I would just call the local variable "locx" or "xx" or something different. I would actually rather see the "this." shadow escaping be disallowed.

In the above code snip it seems that properties will be public unless listed as private. In the security world, whitelisting is considered a best practice as blacklisting can accidentally leave things out in public that should not be. Whitelisting inside a class would be explicitly labeling things as public.

Going with a default-private, whitelisting system we would have...

class Point { var x = Math.random(); public function getX(){ return this.x; } ... }

This is problematic as "var" is being used to define a variable with scope inside the class's braces. I don't know if that will fly well and is analogous to the issue discussed lately where "return" inside a "let" statement's block was considered confusing if a "let" desugars to a function. The reasoning being a programmer sees "return" and immediately looks up to the nearest "function" keyword. "var" inside "let" statement is the same issue. Anyway, programmers are currently used to seeing "var" and looking up the nearest "function" keyword. Whether or not programmers can learn to change is an argument I was not successful convincing Brendan about for the "let" situation though he also wants different semantics anyway (and I understand his case.)

I don't know if it makes sense that "let" could be used instead of "var" as "let" declarations scope are the closest surrounding braces? Is it even that simple?

Perhaps just use "private" or "public" instead of "var"?

What about the following two options:

class Point { private x = Math.random(); public function getX(){ return x; }; }

var Point = class { private x = Math.random(); public getX = function(){ return x; }; };

If only one option could be included I'd much prefer the final option as "var" could be changed to "let" so I control the class's scope better.

In either of the last two cases, I imagine that the "Point" variable is pointing to a first-class class objects (which desugars to a constructor function) that I could pass around, yes?

Peter

# Kris Zyp (16 years ago)

I am surprised this is up for debate, I would also think that we would want instance-private by default.

We can debate lots of things, some that might actually be in play. AFAIK this one is not decided in the committee (it's way too early), but IP does have some strong proponents.

AS3, JScript.NET, and Waldemar's original ES4/JS2 work all had CP. Java has CP. So do C++ and C#. It should not come as a surprise, therefore, if CP has at least to be dealt with by some rationale for IP over against CP. "Smalltalk rules" won't cut it ;-).

I'm happy to have a little debate on this topic, given the different precedents. I'm wondering why you think there's no question.

/be

I'm sorry, I had misunderstood. I was thinking CP meant one variable per class (like indicated by "static"), but CP means the scope of who could access the private object property. This is a question worthy of debate. Thanks, Kris

# Brendan Eich (16 years ago)

On Aug 25, 2008, at 12:34 AM, Peter Michaux wrote:

On Sun, Aug 24, 2008 at 9:44 PM, Kris Zyp <kris at sitepen.com> wrote:

Desugared from:

class Point { private var x = Math.random(); function getX(){ return this.x; } ... }

Is there any need for the "this."? Some languages allow "this.x" to get out from under the shadow of a local "x" inside "getX". I don't think it is necessary to be able to escape such shadowing and actually increases confusion. If a method is many lines long then the reader may forget that "x" is local and not the instance variable. I would just call the local variable "locx" or "xx" or something different. I would actually rather see the "this." shadow escaping be disallowed.

That might be a good idea.

The bigger question is whether |this| remains at all. The desugarings
we tend to write on whiteboards use |let self = ...| or similar and | self| as the new |this| -- but of course that might collide with a
necessary inner or outer name. It would be better to gensym the name,
but who has time at a whiteboard?

To refer to the instance in the sugared language, and there are valid
use-cases for doing so, we should use |this|. There's no point in
introducing a new keyword. Which gets to a point you raise later,
about var in class being confusing. If class is the new, higher
integrity constructor function that induces instance-bound frozen
methods, etc., then its syntax (by the similarity principle I
adumbrated earlier) should mimic function:

class Point(x, y) { // parameters to constructor here let r = Math.sqrt(xx + yy); let theta = Math.atan2(y, x); function getX() x; function getY() y; // etc. }

var or const could be used too, because they can be used in function
bodies. Class body is constructor code. Similarity is good because
it builds on JS programmers' knowledge of functions, but provides
incrementally better semantics for the similar syntax. Programmers
get the carrot, not the stick of gratuitously different syntax.

It will take more than a 2D point class to make the case, but this
was along the lines of the Oslo discussions on the third day, to
desugar as Mark proposed on the first (and showed in his post at the
head of this thread).

In the above code snip it seems that properties will be public unless listed as private. In the security world, whitelisting is considered a best practice as blacklisting can accidentally leave things out in public that should not be.

Not everything in JS is security-critical. JS is used in single-trust- domain embeddings, but even on the web, the B&D programming by way of
the security root password to the tattered "just a scripting
language" constitution seems like a power-grab :-P. I mixed three
kinds of technical politics there, but they are all relevant.
Different parties are concerned about the common good, but we don't
all agree on the common good.

Python and Smalltalk don't have private methods by default (or at
all), just to pick two examples. Should classes as better
constructors have this bias?

I'm not saying "no", I reserve judgment. It seems to me much depends
on the module system, if there is one (and there had better be, since
in spite of being the inevitable source of addressing and loading
semantics, the <script> tag is not enough for in-language modularity).

What about the following two options:

class Point { private x = Math.random(); public function getX(){ return x; }; }

Verbose, please pick a default. Making people type private all the
time is going to get old (if you think 'function' is too long...).

var Point = class { private x = Math.random(); public getX = function(){ return x; }; };

This shows a separable and good idea: first-class classes. BTW, you
probably want 'const Point = class { ... }', and 'class Point...'
should make a const binding by default (unlike a function definition
-- another upgrade).

Another separable point to debate: resolved, classes should freely
nest (in other classes and functions) and generate new entities each
time they are evaluated. Just like functions (ignoring or removing
the joined function object option from ES3).

If only one option could be included I'd much prefer the final option as "var" could be changed to "let" so I control the class's scope better.

That's not to say we shouldn't have the named form of class, any more
than we shouldn't have named functions. Named functions are a special
form, as close to let rec as you get in JS. You can have mutually
recursive named functions call one another freely, making forward
refs, due to hoisting.

You also get the intrinsic name, useful for diagnostics at runtime
and harder to infer (really guess, worst-case pick the name of the
most relevant binding) for anonymous functions.

In either of the last two cases, I imagine that the "Point" variable is pointing to a first-class class objects (which desugars to a constructor function) that I could pass around, yes?

Yes.

There are deeper waters to do with types, but this is enough for
classes. Other details need to be worked out, but this is enough to
chew on for now. Thanks,

# Brendan Eich (16 years ago)

On Aug 25, 2008, at 6:39 AM, Kris Zyp wrote:

I am surprised this is up for debate, I would also think that we
would want instance-private by default.

We can debate lots of things, some that might actually be in
play. AFAIK this one is not decided in the committee (it's way too early),
but IP does have some strong proponents.

AS3, JScript.NET, and Waldemar's original ES4/JS2 work all had
CP. Java has CP. So do C++ and C#. It should not come as a surprise,
therefore, if CP has at least to be dealt with by some rationale for IP over
against CP. "Smalltalk rules" won't cut it ;-).

I'm happy to have a little debate on this topic, given the different precedents. I'm wondering why you think there's no question.

/be

I'm sorry, I had misunderstood. I was thinking CP meant one
variable per class (like indicated by "static"), but CP means the scope of who
could access the private object property. This is a question worthy of
debate. Thanks,

Yeah, that confusion happened briefly in Oslo. Class-private vs.
instance-private instance variables might be the long-winded solution
to ambiguity. CPIV vs. IPIV? Yuck.

Properties of the class constructor, with appropriate attributes, AKA
class statics, are not controversial AFAICT. There ought to be sugar.
It might well use the static keyword.

# Peter Michaux (16 years ago)

On Mon, Aug 25, 2008 at 11:28 AM, Brendan Eich <brendan at mozilla.org> wrote:

On Aug 25, 2008, at 12:34 AM, Peter Michaux wrote:

On Sun, Aug 24, 2008 at 9:44 PM, Kris Zyp <kris at sitepen.com> wrote:

Desugared from:

class Point { private var x = Math.random(); function getX(){ return this.x; } ... }

Is there any need for the "this."? Some languages allow "this.x" to get out from under the shadow of a local "x" inside "getX". I don't think it is necessary to be able to escape such shadowing and actually increases confusion. If a method is many lines long then the reader may forget that "x" is local and not the instance variable. I would just call the local variable "locx" or "xx" or something different. I would actually rather see the "this." shadow escaping be disallowed.

That might be a good idea.

The bigger question is whether |this| remains at all. The desugarings we tend to write on whiteboards use |let self = ...| or similar and |self| as the new |this| -- but of course that might collide with a necessary inner or outer name. It would be better to gensym the name, but who has time at a whiteboard?

To refer to the instance in the sugared language, and there are valid use-cases for doing so, we should use |this|. There's no point in introducing a new keyword.

If there is a need to refer to the instance then "this" does make sense. What would be a great success if if there is just no need for "this" at all. It certainly seems possible to avoid.

Which gets to a point you raise later, about var in class being confusing. If class is the new, higher integrity constructor function that induces instance-bound frozen methods, etc., then its syntax (by the similarity principle I adumbrated earlier) should mimic function:

class Point(x, y) { // parameters to constructor here let r = Math.sqrt(xx + yy); let theta = Math.atan2(y, x); function getX() x; function getY() y; // etc. }

I was wondering about how the constructor parameter aspects would work and thought it might work like you have outlined above.

Now there is another problem: differentiating between which variables are local to the constructor function (that is, transient and garbage collected after the constructor function is returned (don't know the technical name for these variables)) and which are properties of the resulting returned object. I think you know what I'm describing but to make it more concrete in ES3 I can write

function Point(rad, ang) { // some helper functions function computeX() { return radMath.cos(ang); } function computeY() { return radMath.sin(ang); } this.x = computeX() this.y = computeY(); }

A naive translation to the sugar might be

class Point(rad, ang) { // some helper functions that end up being properties? Problem. function computeX() { return radMath.cos(ang); } function computeY() { return radMath.sin(ang); } var x = computeX() var y = computeY(); }

Requiring the programmer to use both "public" and "private" as I did below might be a solution (though you thought it is verbose) so that it is clear which variables are part of the constructed objects.

var or const could be used too, because they can be used in function bodies. Class body is constructor code. Similarity is good because it builds on JS programmers' knowledge of functions, but provides incrementally better semantics for the similar syntax. Programmers get the carrot, not the stick of gratuitously different syntax.

It will take more than a 2D point class to make the case, but this was along the lines of the Oslo discussions on the third day, to desugar as Mark proposed on the first (and showed in his post at the head of this thread).

I suggest at least a couple DOM widgets are used (e.g. tabbed pane, dragdrop list, sortable table) as test examples when discussing class sugar seriously. The DOM is a big part of the JavaScript world, after all.

In the above code snip it seems that properties will be public unless listed as private. In the security world, whitelisting is considered a best practice as blacklisting can accidentally leave things out in public that should not be.

Not everything in JS is security-critical. JS is used in single-trust-domain embeddings, but even on the web, the B&D programming by way of the security root password to the tattered "just a scripting language" constitution seems like a power-grab :-P. I mixed three kinds of technical politics there, but they are all relevant. Different parties are concerned about the common good, but we don't all agree on the common good.

Python and Smalltalk don't have private methods by default (or at all), just to pick two examples. Should classes as better constructors have this bias?

My gut says yes and I have some vague reasoning that may mature.

In ES3 a nested function is "private" inside the outer function. So there is some sense of "private by default" already. At least apparently to me.

function foo() { function bar() {} //... }

I have to make special effort to get that bar function out in the open or in some larger surrounding scope.

I'm not saying "no", I reserve judgment. It seems to me much depends on the module system, if there is one (and there had better be, since in spite of being the inevitable source of addressing and loading semantics, the <script> tag is not enough for in-language modularity).

No one seemed to response to my post in the thread about modules but "module" should not equal "file" as HTTP is still expensive and programmers want to concatenate and minify their scripts.

What about the following two options:

class Point { private x = Math.random(); public function getX(){ return x; }; }

Verbose, please pick a default.

Private. Much easier to debug. The issues described above about helper functions may necessitate declaring both public and private properties as such.

Making people type private all the time is going to get old (if you think 'function' is too long...).

I don't think "function" is too long. It is shorter than "procedure" :-) The only unfortunate thing about "function" is they are not really functions.

var Point = class { private x = Math.random(); public getX = function(){ return x; }; };

This shows a separable and good idea: first-class classes. BTW, you probably want 'const Point = class { ... }', and 'class Point...' should make a const binding by default (unlike a function definition -- another upgrade).

Another separable point to debate: resolved, classes should freely nest (in other classes and functions) and generate new entities each time they are evaluated. Just like functions (ignoring or removing the joined function object option from ES3).

Great!

If only one option could be included I'd much prefer the final option as "var" could be changed to "let" so I control the class's scope better.

That's not to say we shouldn't have the named form of class,

No. I was pointing out that having the last form would be really good.

any more than we shouldn't have named functions. Named functions are a special form, as close to let rec as you get in JS. You can have mutually recursive named functions call one another freely, making forward refs, due to hoisting.

You also get the intrinsic name, useful for diagnostics at runtime and harder to infer (really guess, worst-case pick the name of the most relevant binding) for anonymous functions.

In either of the last two cases, I imagine that the "Point" variable is pointing to a first-class class objects (which desugars to a constructor function) that I could pass around, yes?

Yes.

There are deeper waters to do with types,

Yes. The parent-child windows issue both declaring the same or different "class Foo" seems like an important detail. Perhaps provably making nominal types useless or at least as awkward as instanceof?

but this is enough for classes. Other details need to be worked out, but this is enough to chew on for now.

Peter

# Brendan Eich (16 years ago)

On Aug 25, 2008, at 12:23 PM, Peter Michaux wrote:

To refer to the instance in the sugared language, and there are valid use-cases for doing so, we should use |this|. There's no point in introducing a new keyword.

If there is a need to refer to the instance then "this" does make sense. What would be a great success if if there is just no need for "this" at all. It certainly seems possible to avoid.

I don't think so. Standard patterns of delegation (visitor, double- dispatched dyadic operators) must pass |this| whole and intact.

Now there is another problem: differentiating between which variables are local to the constructor function (that is, transient and garbage collected after the constructor function is returned (don't know the technical name for these variables))

Temporaries.

and which are properties of the resulting returned object.

True temporaries might need explicit block scope to avoid being
entrained in closures.

Requiring the programmer to use both "public" and "private" as I did below might be a solution (though you thought it is verbose) so that it is clear which variables are part of the constructed objects.

But the private vars would not be temporary. They would need to live
as long as the instance. It seems to me you're mixing lifetime with
visibility.

I suggest at least a couple DOM widgets are used (e.g. tabbed pane, dragdrop list, sortable table) as test examples when discussing class sugar seriously. The DOM is a big part of the JavaScript world, after all.

Great idea.

A lot of Ajax widgets, e.g. Dojo, use their own inheritance models,
often based on copying properties (sometimes based on prototypes; in
the case of Dojo's MI, both!). Copying is fine for a zero-inheritance
classes-as-sugar proposal. The prototype stuff, as Kris points out,
is different.

In ES3 a nested function is "private" inside the outer function. So there is some sense of "private by default" already.

Lexical scope is great. You have a point.

No one seemed to response to my post in the thread about modules but "module" should not equal "file" as HTTP is still expensive and programmers want to concatenate and minify their scripts.

Oh, absolutely. I made the point in several posts, and Ibad picked up
on it: addressing and loading are outside the core language. The
inside part that's left is about how the importer names (or does not
name) the module, how the module provides what the importer requires,
how eagerly "linking" occurs, whether cycles are allowed (better
be!), etc.

The upshot is that stuff has to be loaded already. You can't block a
script mid-evaluation and go service events (violating run-to- completion or else locking up some or all UI) to load a remote file
on demand.

The only unfortunate thing about "function" is they are not really functions.

Ok, I will bite: what are they?

Another separable point to debate: resolved, classes should freely
nest (in other classes and functions) and generate new entities each time
they are evaluated. Just like functions (ignoring or removing the joined
function object option from ES3).

Great!

I phrased this as a proposition to debate pro or con. I didn't mean
to say it was resolved (but I hope it will be, in Harmony).

There are deeper waters to do with types,

Yes. The parent-child windows issue both declaring the same or different "class Foo" seems like an important detail. Perhaps provably making nominal types useless or at least as awkward as instanceof?

No, nominal types have their uses. In two disjoint globals, loading
code defining the same nominal type should result in two types, not
one -- we don't want to trust the name, or compare the contents. The
name would simply be qualified by some kind of global identifier or
pathname.

Nominal type use-cases for security, which I've mentioned before,
include auditors (www.erights.org/elang/kernel/auditors) and
hybrid information flow systems (www.ics.uci.edu/~franz/Site pubs-pdf/C46Prepub.pdf, see figure 3). When you need type relations
and equivalence based on name bound by special form, it's hard to do
without. As Mark pointed out in Oslo, nominal types plus lexical
scope let human and machine auditors know exactly what
implementation(s) a class has.

One can make nominal types via branding in a structural type system.
There's more to say here, later.

# Kris Zyp (16 years ago)

A lot of Ajax widgets, e.g. Dojo, use their own inheritance models, often based on copying properties (sometimes based on prototypes; in the case of Dojo's MI, both!). Copying is fine for a zero-inheritance classes-as-sugar proposal. The prototype stuff, as Kris points out, is different.

To be clear, we use prototype inheritance as the rule, copying is the exception, only done as needed to acheive MI. I don't think I would characterize prototypical inheritance as Dojo's own, where the inheritance model becomes more library specific is in how constructor calls, super calls, and inheritance trails are handled. However, almost every library I am aware of uses prototype-based inheritance for pseudo-classes, and consequently there is a level of compatibility. Dojo could create a class that extends a Prototype (the library) class, and vice versa (at least theoritically this should be viable without too much problem). This why I would like to ensure that class sugar also used a prototype-based model, so existing class structures are compatible with the new syntax.

Kris

# Peter Michaux (16 years ago)

On Mon, Aug 25, 2008 at 2:01 PM, Brendan Eich <brendan at mozilla.org> wrote:

On Aug 25, 2008, at 12:23 PM, Peter Michaux wrote:

Now there is another problem: differentiating between which variables are local to the constructor function (that is, transient and garbage collected after the constructor function is returned (don't know the technical name for these variables))

Temporaries.

and which are properties of the resulting returned object.

True temporaries might need explicit block scope to avoid being entrained in closures.

Requiring the programmer to use both "public" and "private" as I did below might be a solution (though you thought it is verbose) so that it is clear which variables are part of the constructed objects.

But the private vars would not be temporary.

Correct. Even the temporaries might not be temporary due to closures (see below.)

They would need to live as long as the instance. It seems to me you're mixing lifetime with visibility.

I don't think I am (too) confused. This is the very issue I was trying to raise or muddle through in my mind.

There needs to be a way(s) to distinguish which variables have which lifetimes and visibilities.

The following is no good

class Foo() { var temp = 0; var priv = 1; var pub = 2; }

It could be

class Foo() { var temp = 0; private priv = 1; public pub = 2; }

In the above example, "temp" will be garbage collected and there is no use in the private "priv" variable and it could be garbage collected too.

The situation changes when a public method exists.

class Foo() { var temp = 0; private priv = 1; public pub = function() temp + priv; }

Now "temp" is captured in the closure of "pub" and so "temp" is effectively instance-private. So the "private" keyword isn't necessary at least in terms of lifetime as the following is the same.

class Foo() { var temp = 0; var priv = 1; public pub = function() temp + priv; }

This last example, no "private" keyword, works if instance-private is desired. If class-private is desired (I hope not! as I explained before) then the second to last example above would be required. In which case "var" works like Ruby's "private" (instance-private), "private" works like Ruby's "protected" (class-private) and "public" is like everyone's "public".

So the issue may not be choosing between instance-private or class-private. JavaScript will have instance-private thanks to closures. The question becomes is class-private also desirable, worth the extra keyword and complexity both to learn and to debug?

I favor the last example above, with no class-private, and now my gut feeling that private-by-default is natural for JavaScript has some concrete support.

No one seemed to response to my post in the thread about modules but "module" should not equal "file" as HTTP is still expensive and programmers want to concatenate and minify their scripts.

Oh, absolutely. I made the point in several posts, and Ibad picked up on it: addressing and loading are outside the core language. The inside part that's left is about how the importer names (or does not name) the module, how the module provides what the importer requires, how eagerly "linking" occurs, whether cycles are allowed (better be!), etc. The upshot is that stuff has to be loaded already. You can't block a script mid-evaluation and go service events (violating run-to-completion or else locking up some or all UI) to load a remote file on demand.

I think the ability to have two modules in one file means modules will need to name themselves. That is they will need to be declared with a name like

module foo { // ... }

or

var foo = module { // ... };

The importer could rename things but somehow the importer will have to use the name "foo" to at least start importing.

By cycles you mean module A using module B which uses module A? Late "linking" would required to allow cycles, correct? Also perhaps the "foo" variable may reference different module objects at different times.

The only unfortunate thing about "function" is they are not really functions.

Ok, I will bite: what are they?

Now I regret that statement because I'm in a room full of far more qualified people than I to argue about programming language terminology semantics. I won't chicken out though:

I'd say they are procedures because they carry out a series of steps (a process). A function wouldn't have implicit arguments (i.e. "this"), automatic variables (i.e. "arguments"), or be able to cause side effects. This is why the word "function" has needed to be fortified to "pure function" to mean "a function and we really mean an actual function that take input and produces output without causing any chaos in the mean time." Just to be clear, I'm not a pure functional enthusiast. I don't understand "monads" when a simple "print" will do just fine.

Now I will try to duck the many punches I probably deserve.

Another separable point to debate: resolved, classes should freely nest (in other classes and functions) and generate new entities each time they are evaluated. Just like functions (ignoring or removing the joined function object option from ES3).

Great!

I phrased this as a proposition to debate pro or con. I didn't mean to say it was resolved (but I hope it will be, in Harmony).

If "class" is desugaring to a constructor function then I'd hope everyone agrees.

There are deeper waters to do with types,

Yes. The parent-child windows issue both declaring the same or different "class Foo" seems like an important detail. Perhaps provably making nominal types useless or at least as awkward as instanceof?

No, nominal types have their uses. In two disjoint globals, loading code defining the same nominal type should result in two types, not one -- we don't want to trust the name, or compare the contents.

I agree they would have to be two types. I'm not very interested in types and type checking but I don't think we want to have a situation where people are checking if something is an array by looking for the existence of an "obj.splice" property. Ugg that is gnarly.

The name would simply be qualified by some kind of global identifier or pathname. Nominal type use-cases for security, which I've mentioned before, include auditors (www.erights.org/elang/kernel/auditors) and hybrid information flow systems (www.ics.uci.edu/~franz/Site/pubs-pdf/C46Prepub.pdf, see figure 3). When you need type relations and equivalence based on name bound by special form, it's hard to do without. As Mark pointed out in Oslo, nominal types plus lexical scope let human and machine auditors know exactly what implementation(s) a class has. One can make nominal types via branding in a structural type system. There's more to say here, later.

I'll have to read up...or do some work. Hmmm?

Peter

# Brendan Eich (16 years ago)

On Aug 25, 2008, at 4:57 PM, Peter Michaux wrote:

There needs to be a way(s) to distinguish which variables have which lifetimes and visibilities.

We have ways already: explicit blocks containing let-declared
temporaries; your public to make things visible outside their lexical
scope.

Rules to be worked out, I am going fast here (don't slow me down ;-),
but I do not see the point in reinventing wheels or mixing them into
hybrids.

The following is no good

class Foo() {

BTW, no need for () after the class name -- a bit more sugar.

var temp = 0; var priv = 1; var pub = 2; }

It could be

class Foo() { var temp = 0; private priv = 1; public pub = 2; }

In the above example, "temp" will be garbage collected and there is no use in the private "priv" variable and it could be garbage collected too.

Why reinvent the wheel with "private"? Functions outside of classes
do not capture any such declared bindings.

class Foo { var temp = makeBigObjectGraph(); var nontemp = computeSomeResult(temp); var nontemp2 = computeAnotherResult(temp);

function private_method() {...} public function public_method() {...} }

This is bad. Without inventing more syntax, one way out is to write

class Foo { var nontemp, nontemp2;

{ let temp = makeBigObjectGraph(); nontemp = computeSomeResult(temp); nontemp2 = computeAnotherResult(temp); }

function private_method() {...} public function public_method() {...} }

There are other ways around the unwanted entraining of the big object
graph. You could ask for a constructor function inside the class, as
AS3 and ES4 support. But it's still possible to entrain too much in
such a function, and you can't initialize the member vars directly in
their declarations (this combined with non-null types led to the
"settings" syntax in ES4).

So really, caveat hacker. Closures can hang onto too much memory if
you are not careful.

The situation changes when a public method exists.

class Foo() { var temp = 0; private priv = 1; public pub = function() temp + priv; }

Now "temp" is captured in the closure of "pub" and so "temp" is effectively instance-private. So the "private" keyword isn't necessary at least in terms of lifetime as the following is the same.

class Foo() { var temp = 0; var priv = 1; public pub = function() temp + priv; }

This last example, no "private" keyword,

(Whew.)

works if instance-private is desired. If class-private is desired (I hope not! as I explained before) then the second to last example above would be required. In which case "var" works like Ruby's "private" (instance-private), "private" works like Ruby's "protected" (class-private)

This reminds me of an idea from Dave Herman and Sam Tobin-Hochstadt
to add private syntax for generating Name objects bound to lexical
names (after define-local-member-name in PLT Scheme):

private var priv = 1;

Not exactly the same syntax as you sketched, but you could also
separate name generation from use:

private priv; var priv = 1;

and make other uses in the same lexical scope of the (impossible to
forge as a string) Name object mapped to the 'priv' lexical name.

This could be used for class private, C++ "friend", and other such
use-cases.

and "public" is like everyone's "public".

:-)

So the issue may not be choosing between instance-private or class-private.

That's what I was getting at in an earlier message with the generated
Names for class, friend, etc. private.

JavaScript will have instance-private thanks to closures. The question becomes is class-private also desirable, worth the extra keyword and complexity both to learn and to debug?

It's a good question.

I think the ability to have two modules in one file means modules will need to name themselves. That is they will need to be declared with a name like

module foo { // ... }

or

var foo = module { // ... };

The importer could rename things but somehow the importer will have to use the name "foo" to at least start importing.

I will let Ibad^H^H^H^HIhab jump in here ;-).

By cycles you mean module A using module B which uses module A? Late "linking" would required to allow cycles, correct?

Yes. Any early linking would mean no cycles allowed, leaving us with
second-class modules of the PLT Scheme kind (PLT Scheme has a first- class module system too, called "Units", which does allow cycles). At
this point I should summon and defer to Dave Herman (who may be a bit
too busy to respond, but here's hoping).

Also perhaps the "foo" variable may reference different module objects at different times.

The var foo could be rebound, but modules by default should have
higher integrity than that.

# ihab.awad at gmail.com (16 years ago)

On Mon, Aug 25, 2008 at 5:23 PM, Brendan Eich <brendan at mozilla.org> wrote:

On Aug 25, 2008, at 4:57 PM, Peter Michaux wrote:

I think the ability to have two modules in one file means modules will need to name themselves. That is they will need to be declared with a name like

module foo { // ... }

or

var foo = module { // ... };

The importer could rename things but somehow the importer will have to use the name "foo" to at least start importing.

I will let Ibad^H^H^H^HIhab jump in here ;-).

Hey, I liked that name.... };->

If "module" === "compilation unit" (a position I advocate since, within a compilation unit, there are bunches of other ways to divvy up lexical scopes), then naming what is imported is the responsibility of the hitherto-unspecified "fetchModule()" black hole we talked about earlier. So the module construct (if any) need not, on these grounds, contain any name.

When several modules are put into one compilation unit (essentially === "file") for optimization, the question is whether this needs to be done using "cat" or via some other more sophisticated process. For example, a module can always be wrapped in a function. Hence the import --

var z = importModule(fetchModule('foo.bar.baz'), {x: 3, y: 4});

can be rewritten by the optimization framework into --

var $foo_bar_baz$ = function(x, y) { // The code of "foo.bar.baz" here };

var z = $foo_bar_baz$(3, 4);

This is only a simple example of one way to do it.

Under these circumstances, minifying could be achieved if the symbol export/import mechanism at the module boundaries is idiomatic enough to be statically discernible.

By cycles you mean module A using module B which uses module A? Late "linking" would required to allow cycles, correct?

Yes. Any early linking would mean no cycles allowed, leaving us with second-class modules of the PLT Scheme kind ...

Perhaps I should clarify what I was thinking about here, and see what everyone thinks. Let's consider instances of modules. I'll talk about the 0th instance of module A (say) as A[0]. So we have --

  1. Cycle of module code; different instances --

(someone) --instantiates--> A[0] --instantiates--> B[0] --instantiates--> A[1]

where A[0] and A[1] are isolated instances with no built-in communication paths.

  1. Cycle of module instances --

(someone) --instantiates--> A[0] --instantiates--> B[0] --reuses--> A[0]

In case #2, this can be done by A[0] passing down, during the instantiation of B[0], some reference to (parts of) itself -- typically, some symbols that B[0] needs.

How does this serve the needs at hand?

Ihab

# Erik Arvidsson (16 years ago)

2008/8/25 Kris Zyp <kris at sitepen.com>:

A lot of Ajax widgets, e.g. Dojo, use their own inheritance models, often

based on copying properties (sometimes based on prototypes; in the case of Dojo's MI, both!). Copying is fine for a zero-inheritance classes-as-sugar proposal. The prototype stuff, as Kris points out, is different.

To be clear, we use prototype inheritance as the rule, copying is the

exception, only done as needed to acheive MI. I don't think I would characterize prototypical inheritance as Dojo's own, where the inheritance model becomes more library specific is in how constructor calls, super calls, and inheritance trails are handled. However, almost every library I am aware of uses prototype-based inheritance for pseudo-classes, and consequently there is a level of compatibility. Dojo could create a class that extends a Prototype (the library) class, and vice versa (at least theoritically this should be viable without too much problem). This why I would like to ensure that class sugar also used a prototype-based model, so existing class structures are compatible with the new syntax.

I've been quiet on these threads for a long time but i just wanted to emphasize Kris's point. Whatever we decide to desugar the class syntax into I think it is very important to get this right. We need to make classes work with existing prototype based inheritance chains. I would consider it a failure if I cannot create a class that inherits from dijit.TabPane or from a Prototype UI component for that matter.

I would also like to know more about the arguments why people seem to be set on a zero inheritance class model? Does that imply that one can still achieve inheritance using prototypes or does it mean that inheritance is not desired at all?

# Brendan Eich (16 years ago)

On Aug 25, 2008, at 7:07 PM, Erik Arvidsson wrote:

I've been quiet on these threads for a long time but i just wanted
to emphasize Kris's point. Whatever we decide to desugar the class
syntax into I think it is very important to get this right. We need
to make classes work with existing prototype based inheritance
chains. I would consider it a failure if I cannot create a class
that inherits from dijit.TabPane or from a Prototype UI component
for that matter.

Can you define "inherit" more precisely? If it's a matter of giving
classes .prototype objects, perhaps this could be done (it's
attractive since the built-ins, Object, Date, etc., are classes as
well as constructor functions, which have prototype objects).

I would also like to know more about the arguments why people seem
to be set on a zero inheritance class model? Does that imply that
one can still achieve inheritance using prototypes or does it mean
that inheritance is not desired at all?

No, prototypes are here to stay. There's even Object.create to
relieve prototypers from having to write constructor functions.

The desire to explore ZI is two-fold:

  1. It may help the committee to see the smallest possible proposal,
    and work up from there to SI and MI.

  2. It may help the language to avoid adding another kind of
    inheritance than prototype-based delegation.

# Erik Arvidsson (16 years ago)

2008/8/25 Brendan Eich <brendan at mozilla.org>:

On Aug 25, 2008, at 7:07 PM, Erik Arvidsson wrote:

I've been quiet on these threads for a long time but i just wanted to

emphasize Kris's point. Whatever we decide to desugar the class syntax into I think it is very important to get this right. We need to make classes work with existing prototype based inheritance chains. I would consider it a failure if I cannot create a class that inherits from dijit.TabPane or from a Prototype UI component for that matter.

Can you define "inherit" more precisely? If it's a matter of giving

classes .prototype objects, perhaps this could be done (it's attractive since the built-ins, Object, Date, etc., are classes as well as constructor functions, which have prototype objects).

Inherit as in setting up the [[Prototype]] chain in ES3 speak or as in extending the vtable from other languages.

I would also like to know more about the arguments why people seem to be

set on a zero inheritance class model? Does that imply that one can still achieve inheritance using prototypes or does it mean that inheritance is not desired at all?

No, prototypes are here to stay. There's even Object.create to relieve

prototypers from having to write constructor functions.

The desire to explore ZI is two-fold:

  1. It may help the committee to see the smallest possible proposal, and

work up from there to SI and MI.

  1. It may help the language to avoid adding another kind of inheritance

than prototype-based delegation.

Good to hear that. That fits well with what Kris said and what I also believe in.

# Peter Michaux (16 years ago)

On Mon, Aug 25, 2008 at 7:15 PM, Brendan Eich <brendan at mozilla.org> wrote:

No, prototypes are here to stay. There's even Object.create to relieve prototypers from having to write constructor functions.

The desire to explore ZI is two-fold:

  1. It may help the committee to see the smallest possible proposal, and work up from there to SI and MI.

  2. It may help the language to avoid adding another kind of inheritance than prototype-based delegation.

I find this perspective on classes and SI in Java from James Gosling interesting. These are not James' words exactly but if the author's writing is consistent with James' thoughts this could be taken as a strong warning from someone with a lot of experience regarding SI. I'm not bringing this up for the "implements" and type-checking aspects (a separate issue) but rather just the ZI, SI, and MI issue.

From www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html :

<blockquote>

I once attended a Java user group meeting where James Gosling (Java's inventor) was the featured speaker. During the memorable Q&A session, someone asked him: "If you could do Java over again, what would you change?" "I'd leave out classes," he replied. After the laughter died down, he explained that the real problem wasn't classes per se, but rather implementation inheritance (the extends relationship). Interface inheritance (the implements relationship) is preferable. You should avoid implementation inheritance whenever possible." </blockquote>

Peter

# ihab.awad at gmail.com (16 years ago)

Fwiw --

On Sat, Aug 30, 2008 at 12:58 PM, Peter Michaux <petermichaux at gmail.com> wrote:

From www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html : ... he explained that the real problem wasn't classes per se, but rather implementation inheritance (the extends relationship). Interface inheritance (the implements relationship) is preferable.

I agree -- but only so long as the language gives you an easy way to delegate messages by default to another instance. From where I sit, it seems interface inheritance plus a parsimonious way to say "implements Foo; delegate all the Foo stuff to this.myFoo" would be really helpful if this approach is to be taken seriously.

Ihab

# Peter Michaux (16 years ago)

On Mon, Aug 25, 2008 at 7:15 PM, Brendan Eich <brendan at mozilla.org> wrote:

No, prototypes are here to stay. There's even Object.create to relieve prototypers from having to write constructor functions.

The desire to explore ZI is two-fold:

  1. It may help the committee to see the smallest possible proposal, and work up from there to SI and MI.

  2. It may help the language to avoid adding another kind of inheritance than prototype-based delegation.

In a famous email, which many here have probably read, Alan Kay wrote about leaving inheritance out of "object-oriented programming".

From: userpage.fu-berlin.de/~ram/pub/pub_jf47ht81Ht/doc_kay_oop_en

<blockquote>

  • I didn't like the way Simula I or Simula 67 did inheritance (though I thought Nygaard and Dahl were just tremendous thinkers and designers). So I decided to leave out inheritance as a built-in feature until I understood it better. </blockquote>

This conservative approach seems apt for the situation of classes and inheritance in ECMAScript. If classes are to be merely sugar for other language features (purely ES3.1 features?), we don't know exactly what those other parts are and have no experience seeing what is possible with those, then we certainly don't understand how inheritance fits into either the desugared or sugar pictures. It could be that the boilerplate that inheritance tries to solve is not a big problem as I tried to show in the observer pattern example. It seems reasonable to follow Alan's conservative approach before jumping into the deep water of inheritance which has a variable track records.

Peter

# Erik Arvidsson (16 years ago)

If you take the subject and event example and scale that up ten fold so that the object has 20 methods instead of 2 the code quickly becomes hard to maintain and the size over the wire increases quickly. I think what Ihab said points this out clearly and without a good forwarding mechanism ZI seems unmaintainable.

# P T Withington (16 years ago)

On 2008-08-25, at 17:26EDT, Kris Zyp wrote:

This why I would like to ensure that class sugar also used a
prototype-based model, so existing class structures are compatible
with the new syntax.

[Late to the party..., perhaps the dishes have already been cleared?]

Me too. If classes are sugar, I would want them to be sugar for
prototype-based inheritance. If that is compatible with 'zero class- based inheritance', fine.

Whether classes are sugar or not, I would not want them to be used for
access control. I'm against instance-private. I'd much rather see an
orthogonal module system for controlling access/visibility.

Finally, if classes are sugar, they should not be creating some magic
'auto-binding method extraction'. I'd like to see us do away with
'this' as much as anyone else, but not by sweeping it under the
covers. I'd much rather make 'this' explicit and just declare that:

foo.bar(...)

is sugar for:

bar(this=foo, ...)

and

bar(...)

is sugar for

bar(this=undefined, ...)


I hear that this is not a vote, so a bit of rationale:

Like many other AJAX frameworks, we found straight prototype-based
programming too verbose. We invented a class syntax (modeled on es4)
and wrote a translator that 'de-sugars' that into prototype-based
inheritance. We've recently brought our translator up to speed to be
able to translate to as3 (prototype es4, to me), and there was very
little pain in adapting our class system to map to either prototype-
or class-based inheritance. For the work that we want to do, they are
equivalent.

Since desugaring to closures seems to be mostly about creating private
instance variables, if you separate out the access control issue from
your classes, there seems little motivation for that approach.

The 'this' riff is just a personal peeve. As someone else said on the
list, you are not going to get everyone to agree what object-oriented
means. But to me, it definitely does not mean that methods belong to
instances. If methods don't belong to instances, what could 'this'
possibly refer to?