On class literals possibly not making it into ECMAScript.next

# Axel Rauschmayer (13 years ago)

brendaneich.com/2011/10/jsconf-eu

I’d be sad not to have class literals in JavaScript. However, with the new object literal extensions, things are still much better than in ES5. Compare: The ES5 version is clumsy.

// Super
function Person(name) {
    this.name = name;
}
Person.prototype.describe = function() {
    return "Person called "+this.name;
};

// Sub
function Employee(name, title) {
    Person.call(this, name);
    this.title = title;
}
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.describe = function() {
    return Person.prototype.describe.call(this)+" ("+this.title+")";
};

The ES.next version is quite nice:

// Super
function Person(name) {
    this.name = name;
}
Person.prototype .= {
    describe() {
        return "Person called "+this.name;
    }
}

// Sub
Person <| function Employee(name, title) {
    super(name);
    this.title = title;
}
Employee.prototype .= {
    describe() {
        return super.describe(this)+" ("+this.title+")";
    }
};

This is not bad at all, quite teachable! Having a single construct instead of piecing things together via multiple assignments might be a problem in some cases. Then you could use the latest incarnation of Allen’s class pattern:

Person <| function Employee(name, title) {
    super(name);
    this.title = title;
}.={
    prototype.={
        describe() {
            return super.describe(this)+" ("+this.title+")";
        }
    }
    // “class” variables go here
}

[I’m using the destructive version of the extension operator, as shown in Brendan’s blog post]

# Brendan Eich (13 years ago)

On Oct 28, 2011, at 8:23 PM, Axel Rauschmayer wrote:

The ES.next version is quite nice:

[Snip]

I have to say Allen's use of chained <| and .{ wins if you are going for a "class pattern".

There are lots of patterns. It still seems to me we would help more users avoid mistakes by having real class syntax. More on that in a bit.

# Andrea Giammarchi (13 years ago)

Just as curiosity, and I may probably simply read the draft about it, in JS today we borrow methods no matter which prototype they are related ... eg myobj.push = [].push

I wonder if this super() works as parent or if it works as "static", as example, in PHP 5+ world where static::method()

would refer to the current instance parent/super class rather than the one referenced when this method has been created.

As summary, I would like to know if a mixin could be defined in this way:

var object = { genericMethod: function (...args) { super(...args); } };

SomeSubClass.prototype.genericMethod = genericMethod;

Thanks for any sort of clarification.

Best , Andrea Giammarchi

# Axel Rauschmayer (13 years ago)

As summary, I would like to know if a mixin could be defined in this way:

var object = { genericMethod: function (...args) { super(...args); } };

SomeSubClass.prototype.genericMethod = genericMethod;

Object.defineMethod(SomeSubClass.prototype, 'genericMethod', genericMethod); See: harmony:object_initialiser_super#imperatively_binding_super

Also: see thread “Super-calls” that started Oct 1. Summary: true generic |super| hardly ever makes sense. Do you have a concrete example where you need it?

It might make sense to allow one to reimplement |super| (one use case that comes to my mind is implementing multiple dispatch in JavaScript).

# Andrea Giammarchi (13 years ago)

some sort of abstraction could use it and actually static in PHP is more like this in JS so that was a wrong example.

I am just wondering if this super, if defined dynamically per each function call that uses it, won't slow down things as arguments does.

I agree that cases may be few but just think about mixins and mixins created through inheritance.

function Point(x, y) { this.x = x; this.y = y; } Point.prototype.isPositive = function () { return -1 < this.x && -1 < this.y; };

Point <| function 3DPoint(x, y, z) { super(x, y); this.z = z; } 3DPoint.prototype.isPositive = function () { return super() && -1 < this.z; };

Now try to imagine many other object would like to implement the 3Dpoint#isPositive method using 3DPoint as interface but without necessarily extending it .... blah, I know this example is crap so I will think about a better one.

function Entity() {} // no point by default Entity.prototype.setPoint = function (x, y, z) { 3DPoint.call(this, x, y, z); this.hasPoint = true; return this; }; Entity.prototype._isPositive = 3DPoint.prototype.isPositive; Entity.prototype.isPositive = function () { return this.hasPoint && this._isPositive(); }; Entity.prototype.hasPoint = false;

(new Entity).setPoint(1, 2, 3).isPositive(); // boom ? or super is bound to Point ?

br, Andrea Giammarchi

# Axel Rauschmayer (13 years ago)

Sorry for sounding harsh, but I’m really just curious: The example below seems awfully contrived (wouldn’t even single inheritance easily do?) and I don’t see |super| anywhere in it. Have you ever found the need for |super| in a generic function?

Even when we get traits, I don’t see myself as ever needing super-calls in trait methods. That’s because |super| is a construct for subclasses, while traits, in a way, are abstract superclasses.

# David Bruant (13 years ago)

Le 29/10/2011 05:45, Brendan Eich a écrit :

On Oct 28, 2011, at 8:23 PM, Axel Rauschmayer wrote:

I’d be sad not to have class literals in JavaScript. However, with the new object literal extensions, things are still much better than in ES5. Compare: The ES5 version is clumsy. The ES.next version is quite nice: [Snip]

I have to say Allen's use of chained <| and .{ wins if you are going for a "class pattern".

There are lots of patterns. It still seems to me we would help more users avoid mistakes by having real class syntax. More on that in a bit. (emphasis added)

At the top of the classes strawman [1] is written the following: "ECMAScript already has excellent features for defining abstractions for kinds of things. The trinity of constructor functions, prototypes, and instances are more than adequate for solving the problems that classes solve in other languages. The intent of this strawman is not to change those semantics. Instead, it’s to provide a terse and declarative surface for those semantics so that programmer intent is expressed instead of the underlying imperative machinery."

When I see the Triange-Monocle-Moustache combo for a class-like pattern, it seems to me that the goal is very close to be achieved.

What do "real class literal" and "real class syntax" mean (in the previous quotes)? What more would they achieve regarding the goal stated in the classes strawman?

David

[1] harmony:classes

# Andrea Giammarchi (13 years ago)

I sai the example was crap indeed and it doe not matter what it does but how and there is a super call. Will super be assigned runtime or fixed in method creation ?

# David Bruant (13 years ago)

Le 29/10/2011 05:23, Axel Rauschmayer a écrit :

brendaneich.com/2011/10/jsconf-eu

Brendan Eich in the article:

Much of the Dart dartlang.org class syntax design looks good to me. Possibly TC39 can agree to adopt it, with necessary adjustments. It would still be sugar for constructors and prototypes. (It can be found at [1]) What are the parts of the design that look good to you? What are the adjustments you can think of now?

My take on it is that:

  • Differenciating public/private with an underscore (_) seems like a bad idea since if people try to automatically transition JS code to Dart, some variable will have ambiguities and it may lead to bugs that are hard to find. Also, semanticly signifiant identifiers prefix doesn't exist yet in JS.
  • On private fields, I really wonder how these are currently translated into JS, because private fields on objects can't exist if methods are on the prototype. Unless there are weakmaps (with leaks in environment with no weakmap). Or maybe methods are not on the prototype (which would differ from the semantics ES wants to give to class methods and have a memory cost as well)
  • "var" for attribute declaration seems to be at the opposite of the intent of "let is the new var" for ES.next
  • Imposing to name a constructor (or several) and not being able to pass arguments to the class name when used with "new" sounds weird (that's what I understand based on the examples).

Besides these parts, we're left with a "class" keyword and a declarative syntax, some sugar for getter/setter which I agree with but is already in the classes strawman.

David

[1] www.dartlang.org/docs/getting-started/class.html

# Jake Verbaten (13 years ago)

Whilst on the topic of object literal extensions, did we make any progress on supporting what allen calls exemplarsesdiscuss/2011-October/017369 ?

let Employee = Person <| { constructor(name, title) { super(name); this.title = title; }, describe() { return super.describe(this) + " (" + this.title + ")"; } };

# Allen Wirfs-Brock (13 years ago)

On Oct 29, 2011, at 7:48 AM, Andrea Giammarchi wrote:

I sai the example was crap indeed and it doe not matter what it does but how and there is a super call. Will super be assigned runtime or fixed in method creation ?

This is explained in harmony:object_initialiser_super

The summary answer is "fixed in method creation" (which in reality occurs at runtime...)

 super.foo();

means something very similar to

 referenceToAnObjectThatIsDetermineWhenTheMethodIsDefined.foo.call(this);

If you want to do mixins that rebind super you would have to do something like:

function combineMixins(mixinParent, ...mixins) { var mixinHolder = mixinParent <| {}; //create object into which mixins are merged for (var mx in mixins) { for (var methodName in Object.getOwnPropertyNames(mx)) { //ignoring possibility of name conflicts for this example Object.defineMethod(mixinHolder,methodName,mx[methodName]); } } return mixinHolder; }

and you might use it like:

var objWithInheritedMixins = combineMixins(prototype,mixin1,mixin2,mixin3) <| { ownMethod1 () {}, ownMethod2() {} };

# Brendan Eich (13 years ago)

On Oct 29, 2011, at 8:03 AM, David Bruant wrote:

Le 29/10/2011 05:23, Axel Rauschmayer a écrit :

brendaneich.com/2011/10/jsconf-eu Brendan Eich in the article: Much of the Dart class syntax design looks good to me. Possibly TC39 can agree to adopt it, with necessary adjustments. It would still be sugar for constructors and prototypes. (It can be found at [1]) What are the parts of the design that look good to you?

I wrote "much of the ... class syntax" intentionally. All three of the significant words there, combined!

Plus, I was being positive. I do think Dart has some syntactic wins. Not all (e.g. mandatory semicolons) can be worked into Harmony.

What are the adjustments you can think of now?

My take on it is that:

  • Differenciating public/private with an underscore (_) seems like a bad idea since if people try to automatically transition JS code to Dart, some variable will have ambiguities and it may lead to bugs that are hard to find. Also, semanticly signifiant identifiers prefix doesn't exist yet in JS.

Right, that's semantics as well as syntax, not included in my "much".

  • On private fields, I really wonder how these are currently translated into JS, because private fields on objects can't exist if methods are on the prototype. Unless there are weakmaps (with leaks in environment with no weakmap).

We have private name objects, but the this[px], this[py] verbosity I showed is pretty bad. Can we do better?

Or maybe methods are not on the prototype (which would differ from the semantics ES wants to give to class methods and have a memory cost as well)

No, methods are on the prototype. No second object system with different inheritance rules, as I blogged -- sugar for constructors and prototypes. That's semantics again, though.

  • "var" for attribute declaration seems to be at the opposite of the intent of "let is the new var" for ES.next

Yes, 'var' is a bad word on TC39 and we probably don't need it, even if a new class syntax proposal lines up better with Dart, or just learns from it.

  • Imposing to name a constructor (or several) and not being able to pass arguments to the class name when used with "new" sounds weird (that's what I understand based on the examples).

I'm not sure what you mean by ``not being able to pass arguments to the class name when used with "new"''. This works fine at dartlang.org/:

class C { var a, b; C(this.a, this.b){} } main() { var c = new C(1, 2); print(c.a + c.b); }

Besides these parts, we're left with a "class" keyword and a declarative syntax, some sugar for getter/setter which I agree with but is already in the classes strawman.

There's also shorter method syntax where the body is an expression.

But mainly, the point is that classes in ES6 are in trouble. Yet Dart is class-based, reminiscent of Strongtalk but with terse-yet-Java-like syntax. If classes are good enough in Dart, especially in lacking read-before-initialize barriers, then perhaps the same can be true of ES6's proposal.

Perhaps Dart syntax (ignoring private _) doesn't help if you've bought into ES6 class syntax, but not everyone on TC39 has so bought. There' s a lack of conceptual integrity, a fragmented or minimized feel, to the current design. It's a compromise.

Dart is not perfect either but it hangs together slightly better. It's not to my taste, and I don't see it replacing JS by acclamation, but again: can we improve ES6 classes by reflecting on what's good in it?

# Axel Rauschmayer (13 years ago)

There are two things is JavaScript that are simple and elegant and universally liked:

  • Prototypes
  • Object literals

How come we can’t transport that simplicity to classes? Once the objects have been created, we are happy with them, but how to best set them up is still controversial. Are we overthinking classes?

# Greg Smith (13 years ago)

I've been lurking on this mailing list for awhile but just wanted to speak up to say that I think Axel sums up a lot of my feelings about JavaScript and classes. Sorry if I'm speaking out of turn and without context, just wanted to throw my thoughts out there anyway.

Anyway, prototypes are good and object literals are good. I think a lot of the class love is about syntax: they are tidy and self-evident. Object literals are also tidy and self-evident. Prototypes are just messy as they stand in JS. I've taken to enjoying a pattern where you can use object literals to define objects and still get inheritance using prototypes. You've probably seen this type of thing before:

var Person = Animal.inherit({ getName: function() { return this.name; } });

var bob = Person.inherit({ name: 'Bob' });

bob.getName(); // Bob

I have some code to provide this type of pattern here incompl/super-inherit/blob/master/demo.js

But what I'm really getting at is that I think if JavaScript made it this neat and tidy to do prototypal inheritance there might be less clamoring for classes.

Also, I think having super would help a lot.

Anyway that's my two cents.

# Axel Rauschmayer (13 years ago)

Anyway, prototypes are good and object literals are good. I think a lot of the class love is about syntax: they are tidy and self-evident. Object literals are also tidy and self-evident. Prototypes are just messy as they stand in JS. I've taken to enjoying a pattern where you can use object literals to define objects and still get inheritance using prototypes. You've probably seen this type of thing before:

var Person = Animal.inherit({ getName: function() { return this.name; } });

var bob = Person.inherit({ name: 'Bob' });

bob.getName(); // Bob

I have some code to provide this type of pattern here incompl/super-inherit/blob/master/demo.js

But what I'm really getting at is that I think if JavaScript made it this neat and tidy to do prototypal inheritance there might be less clamoring for classes.

I agree. Note that you can do the above already with the <| operator. You just can’t use new Person() to create new instances:

var Person = Animal <| { getName: function() { return this.name; } };

var bob = Person <| { name: 'Bob' };

bob.getName(); // Bob

I still like tremendously that the same mechanism can be used for “subclassing” and for creating an instance directly.

Also, I think having super would help a lot.

It seems to be a done deal for ES.next and is not tied to classes!

# Alex Russell (13 years ago)

On Oct 29, 2011, at 4:03 PM, Axel Rauschmayer wrote:

There are two things is JavaScript that are simple and elegant and universally liked:

  • Prototypes
  • Object literals

Omitting "first class functions" from the list is really problematic.

# Quildreen Motta (13 years ago)

On 29/10/11 21:03, Axel Rauschmayer wrote:

There are two things is JavaScript that are simple and elegant and universally liked:

  • Prototypes
  • Object literals

How come we can’t transport that simplicity to classes? Once the objects have been created, we are happy with them, but how to best set them up is still controversial.

I still maintain that JS doesn't really need a declarative syntax for defining relationships between objects — call it classes if you will. What I really find lacking in the language are primitives that allow me to work with objects, by composing them, querying them, filtering them, whatever-ing them.

I think people already stressed enough the why of having a declarative syntax for all that (tooling, describing intent, simplicity, etc, etc). But there's also value in not having another full-blown and different syntax, imho, as we already have the triangle operator(?), the monocle-moustache operator(?) and object literals.

Now, for the past few months, I've been defining my objects like this:

// where `clone' = Object.extend(Object.create(proto), props) var Thing = function(){ return ( { clone: _clone , toString: toString })

function clone(name){ return clone(Thing, { name: name }) } function toString() { return '[thing ' + this.name + ']' } }()

var Specific = function(){ return clone(Thing, { clone: _clone , toString: toString })

function clone(name){ return clone(Specific, { name: name }) } function toString() { return '[specific ' + this.name + ']' } }()

var foo = Thing.clone('foo') var bar = Specific.clone('bar')

/// Using an extended version of object literals var Thing = { constructor(name){ this.name = name } ,toString(){ return '[thing ' + this.name + ']' } }

var Specific = Thing <| { constructor(name){ this.name = name } ,toString(){ return '[specific ' + this.name + ']' } }

var foo = new Thing('foo') var bar = new Specific('foo')

// Clear advantages: // - Familiar syntax, whilst managing to be quite okay to work with // - Declarative, but not static // // Clear disadvantages: // - Using `new' in this fashion would require changing semantics for objects // - Kinda conflicts with constructor functions. I'd think that factories // living inside objects and always creating new instances would be // better, but I know old semantics won't be changed =/

/// Using class syntax class Thing { constructor(name){ this.name = name } toString(){ return '[thing ' + this.name + ']' } }

class Specific extends Thing { constructor(name){ this.name = name } toString(){ return '[specific ' + this.name + ']' } }

// Clear advantages: // - Cleaner // - Can be easily extended to support sugars for traits, privates, and what-nots // // Clear disadvantages: // - Unfamiliar syntax (for the language itself, not for other languages) // - Fixed syntax // - Some could argue the name is quite misleading given the semantics, but I digress.

Now, I'm not sure class-syntax alone solve the main problems of working with objects and structuring programs in JavaScript — unless you always structure your programs using a huge inheritance tree, I favour object composition, so the class-syntax doesn't change much of what I find particularly counter-productive in the language. Other people's mileage may vary.

Anyways, what I feel the language should provide for aiding in the structure programs is:

  • A way of sharing behaviour — semantically covered by prototypes, and the <| operator is a nice interface for Object.create.
  • A way of composing behaviours — traits and mixins. The latter is already widely used, afaics. Also the .{ operator.
  • A set of primitives for working with objects as sets — join, difference and intersection operations, for example.

With class-syntax you can provide a nice interface to all those, but I believe the extension proposals to the Object literal already covers such cases as well, such that you'd get duplicated syntatical sugar for the same thing.

The major difference I see is that class-syntax, once defined, will be fixed. They might cover most cases now, but that might not necessarily hold true as the language and programmers evolve. Providing primitives — they're mostly independent from class-syntax anyways, which is cool — allows programmers to evolve the patterns on their own as well.

The one thing class-syntax would excel at, though, is the current semantics for super calls in ES.next. I find them particularly confusing, considering the relationship between functions and objects in JS. They make more sense with a static declarative syntax, but that might be just me.

None the less, I believe the entry-barrier to both the object literal syntax and class-syntax to be in the same level, only the class-syntax looks cleaner and more elegant.

Are we overthinking classes?

Perhaps the reason for all this thinking about classes come from the role constructor functions take in the language? I'm a bit sceptical on constructors and constructor's own properties being that important, though.

# Axel Rauschmayer (13 years ago)

Now, for the past few months, I've been defining my objects like this:

// where `clone' = Object.extend(Object.create(proto), props) var Thing = function(){ return ( { clone: _clone , toString: toString })

function clone(name){ return clone(Thing, { name: name }) } function toString() { return '[thing ' + this.name + ']' } }()

var Specific = function(){ return clone(Thing, { clone: _clone , toString: toString })

function clone(name){ return clone(Specific, { name: name }) } function toString() { return '[specific ' + this.name + ']' } }()

var foo = Thing.clone('foo') var bar = Specific.clone('bar')

Where is _clone in the above code? You also could write the functions into the object literals then you wouldn’t need an IIFE.

How about the following variation of your code? Would that still reflect your intentions or go against your taste? It’s very close to your next proposed solution.

var Clonable = {
    clone: function() {
        var inst = Object.create(this);
        inst.init.apply(inst, arguments);
    },
    extend: function(props) {
        return  Object.extend(Object.create(this), props);
    },
}

var Thing = Clonable.extend({
    init: function (name) {
        this.name = name;
    },
    toString: function () {
        return '[thing ' + this.name + ']';
    },
});

var Specific = Thing.extend({
    // reuse Thing.init()
    toString: function () {
        return '[specific ' + this.name + ']';
    },
});

var foo = Thing.clone('foo')
var bar = Specific.clone('bar')

/// Using an extended version of object literals var Thing = { constructor(name){ this.name = name } ,toString(){ return '[thing ' + this.name + ']' } }

var Specific = Thing <| { constructor(name){ this.name = name } ,toString(){ return '[specific ' + this.name + ']' } }

var foo = new Thing('foo') var bar = new Specific('foo')

That’s approximately how Irakli’s Selfish or my Prototypes as Classes work (both are ES5 libraries).

The one thing class-syntax would excel at, though, is the current semantics for super calls in ES.next. I find them particularly confusing, considering the relationship between functions and objects in JS. They make more sense with a static declarative syntax, but that might be just me.

Super-calls are the one thing that would stay the same between all current proposals!

# David Bruant (13 years ago)

Le 30/10/2011 02:35, Quildreen Motta a écrit :

(...)

Are we overthinking classes?

Perhaps the reason for all this thinking about classes come from the role constructor functions take in the language? I'm a bit sceptical on constructors and constructor's own properties being that important, though.

I agree. Has anyone used constructor properties for "static" properties? Just considering the DOM, constants are put on the prototype and everyone sounds happy with it so far.

# Rick Waldron (13 years ago)

On Oct 30, 2011, at 5:58 AM, David Bruant <bruant.d at gmail.com> wrote:

Le 30/10/2011 02:35, Quildreen Motta a écrit :

(...)

Are we overthinking classes?

Perhaps the reason for all this thinking about classes come from the role constructor functions take in the language? I'm a bit sceptical on constructors and constructor's own properties being that important, though. I agree. Has anyone used constructor properties for "static" properties? Just considering the DOM, constants are put on the prototype and everyone sounds happy with it so far.

In jQuery, John/we put "static" methods and properties

# Quildreen Motta (13 years ago)

On 30/10/11 01:07, Axel Rauschmayer wrote:

Now, for the past few months, I've been defining my objects like this:

// where `clone' = Object.extend(Object.create(proto), props) var Thing = function(){ return ( { clone: _clone , toString: toString })

function clone(name){ return clone(Thing, { name: name }) } function toString() { return '[thing ' + this.name + ']' } }()

var Specific = function(){ return clone(Thing, { clone: _clone , toString: toString })

function clone(name){ return clone(Specific, { name: name }) } function toString() { return '[specific ' + this.name + ']' } }()

var foo = Thing.clone('foo') var bar = Specific.clone('bar') Where is _clone in the above code? You also could write the functions into the object literals then you wouldn’t need an IIFE.

Ah, those clone' functions should be_clone'. The underscore is just to avoid conflicts with the outer `clone' function.

Anyways, it is a matter of taste. I write function-heavy style, so I find it better to write something(other(x)) than this.something(this.other(x)). Defining the objects inside a closure allows me to define these little helper functions that would otherwise just clobber the prototype object if exposed — I usually expose them under a `internal' property though, so I can test them.

There's also the thing about my liking to have a list of all public properties of the object readily accessible in the code. With object literals it gets a bit more difficult, as the list of properties are lost in the definitions of such properties.

How about the following variation of your code? Would that still reflect your intentions or go against your taste? It’s very close to your next proposed solution.

 var Clonable = {
     clone: function() {
         var inst = Object.create(this);
         inst.init.apply(inst, arguments);
     },
     extend: function(props) {
         return  Object.extend(Object.create(this), props);
     },
 }

 var Thing = Clonable.extend({
     init: function (name) {
         this.name = name;
     },
     toString: function () {
         return '[thing ' + this.name + ']';
     },
 });

 var Specific = Thing.extend({
     // reuse Thing.init()
     toString: function () {
         return '[specific ' + this.name + ']';
     },
 });

 var foo = Thing.clone('foo')
 var bar = Specific.clone('bar')

/// Using an extended version of object literals var Thing = { constructor(name){ this.name = name } ,toString(){ return '[thing ' + this.name + ']' } }

var Specific = Thing<| { constructor(name){ this.name = name } ,toString(){ return '[specific ' + this.name + ']' } }

var foo = new Thing('foo') var bar = new Specific('foo') That’s approximately how Irakli’s Selfish or my Prototypes as Classes work (both are ES5 libraries).

Yes, and to which I think class-syntax would be just a duplicated sugar — as long as you have the new <| and .{ operators, that is.

The one thing class-syntax would excel at, though, is the current semantics for super calls in ES.next. I find them particularly confusing, considering the relationship between functions and objects in JS. They make more sense with a static declarative syntax, but that might be just me. Super-calls are the one thing that would stay the same between all current proposals!

Hm, wouldn't most features covered by the class-syntax be independent of syntax in the end? My point was that the nature of static |super| fits more naturally the static nature of the class-syntax than the dynamic nature of prototypes, even though object literals are declarative. People are likely to think about class-syntax in the same manner they reason about them in classical languages, I guess.

# Jake Verbaten (13 years ago)

On Sun, Oct 30, 2011 at 11:45 AM, Rick Waldron <waldron.rick at gmail.com>wrote:

On Oct 30, 2011, at 5:58 AM, David Bruant <bruant.d at gmail.com> wrote:

Le 30/10/2011 02:35, Quildreen Motta a écrit :

(...)

Are we overthinking classes?

Perhaps the reason for all this thinking about classes come from the role constructor functions take in the language? I'm a bit sceptical on constructors and constructor's own properties being that important, though. I agree. Has anyone used constructor properties for "static" properties? Just considering the DOM, constants are put on the prototype and everyone sounds happy with it so far.

In jQuery, John/we put "static" methods and properties on the jQuery() function - this practice is used for anything that is not a selector match operation. This includes Ajax and Deferred (among others). Considering jQuery is used on >26.6million websites, it's safe to bet that practice is in common use.

Would there be anything wrong with placing these "static methods" on the prototype? I presume there is also nothing wrong with placing DOM constants on the prototype?

# Quildreen Motta (13 years ago)

On 30/10/11 09:45, Rick Waldron wrote:

On Oct 30, 2011, at 5:58 AM, David Bruant<bruant.d at gmail.com> wrote:

Le 30/10/2011 02:35, Quildreen Motta a écrit :

(...)

Are we overthinking classes? Perhaps the reason for all this thinking about classes come from the role constructor functions take in the language? I'm a bit sceptical on constructors and constructor's own properties being that important, though. I agree. Has anyone used constructor properties for "static" properties? Just considering the DOM, constants are put on the prototype and everyone sounds happy with it so far.

In jQuery, John/we put "static" methods and properties on the jQuery() function - this practice is used for anything that is not a selector match operation. This includes Ajax and Deferred (among others). Considering jQuery is used on>26.6million websites, it's safe to bet that practice is in common use.

Rick

Ah, when I said `important' I didn't mean in the sense of how much people use it. I meant that the functionality can be achieved with or without constructors.

The only thing that changes is the order of importance of things. With constructors, the major player are functions — which arguably makes the semantics of prototypes a bit weird:

function Thing(parent, name) { // instance properties this.name = name this.childs = [] if (parent) parent.childs.push(this) }

// constructor properties Thing.sort = function(thing){ thing.childs.sort(function(o1, o2){ return o1.name < o2.name }) return thing }

// shared instance properties Thing.prototype.sort = function(){ return Thing.sort(this) }

var something = new Thing(null, 'something') something.sort() Thing.sort(something)

With objects as the major players, you still get "static" properties, due to the nature of delegative behaviour sharing that [[Prototype]] has, it's just a little different:

Thing = { // instance properties new: function(parent, name) { this.name = name this.childs = [] if (parent) parent.childs.push(this) },

// shared instance properties sort: function() { this.childs.sort(function(o1, o2){ return o1.name < o2.name }) return this },

// "constructor" properties static: { sort: function(thing) { return Thing.sort.call(thing) } } }

var something = Thing.new(null, 'something') something.sort() something.static.sort(something)

Of course, people seem to be too used to the class-like way of doing things, that proposing such could be regarded as "madness". Plus, getting rid of constructors is not reasonable at this point in time; as Brendan said, we're basically stuck with every semantic quirk the language has got so far.

# Rick Waldron (13 years ago)

On Sun, Oct 30, 2011 at 1:18 PM, Jake Verbaten <raynos2 at gmail.com> wrote:

On Sun, Oct 30, 2011 at 11:45 AM, Rick Waldron <waldron.rick at gmail.com>wrote:

On Oct 30, 2011, at 5:58 AM, David Bruant <bruant.d at gmail.com> wrote:

Le 30/10/2011 02:35, Quildreen Motta a écrit :

(...)

Are we overthinking classes?

Perhaps the reason for all this thinking about classes come from the role constructor functions take in the language? I'm a bit sceptical on constructors and constructor's own properties being that important, though. I agree. Has anyone used constructor properties for "static" properties? Just considering the DOM, constants are put on the prototype and everyone sounds happy with it so far.

In jQuery, John/we put "static" methods and properties on the jQuery() function - this practice is used for anything that is not a selector match operation. This includes Ajax and Deferred (among others). Considering jQuery is used on >26.6million websites, it's safe to bet that practice is in common use.

Would there be anything wrong with placing these "static methods" on the prototype?

Everything jQuery defines is done so under a single namespace, which is actually the jQuery() "constructor" (the jQuery function actually returns instances of itself, to avoid requiring "new")

Since all jQuery function calls return, as a new instance, an array like object of matching elements...

jQuery(selector);

// [ node, node, node ]

...All prototype methods are expected to do DOM operations, that return the same array like object of nodes, like so...

jQuery(selector).hide()

// [ node, node, node ]

For non-DOM operations, we put the other modules, functions and constructors on jQuery as "static" properties (maintaining the single Identifier namespace)

The ajax module lives at...

jQuery.ajax( options ); // returns new XHR promise

The deferred constructor...

jQuery.Deferred() // returns new promise

The event constructor...

jQuery.Event() // returns new event object

This pattern makes is very easy for newer developers/adopters to understand the division of functionality:

  • DOM methods here: jQuery().foo()
  • Everything else here: jQuery.bar()

/Rick

I presume there is also nothing wrong with placing DOM constants on the

# Axel Rauschmayer (13 years ago)

But isn’t jQuery.bar() just a work-around, because JavaScript does not have modules, yet?

# Rick Waldron (13 years ago)

No, not at all. It's a conscious design decision that results in only introducing one new property to the global object (two if you count the shorthand reference to $)

# Axel Rauschmayer (13 years ago)

When I see singleton objects in JavaScript, I mostly consider them poor man’s modules (including the Object.* methods).

You could write a jQuery module that exports the “everything else” functions and the identifiers $ and jQuery for the DOM stuff.

# Rick Waldron (13 years ago)

...But that's not the point. The point is to have a single namespaced, unified API; this helps keep the library small, reduces potential conflict with other libs, makes it easier to learn, easier to extend and easier to maintain.

jQuery deals in reality, not the fantasy world of spec drafts and syntax bikeshedding, and that reality is the web today. To be clear, you're aware that jQuery supports a completely compatible API across all browsers that it supports, right? That means that nothing goes into jQuery that cannot be reproduced in...

IE 6, 7, 8 & 9 Firefox 3.6, 6 & 7 Chrome 14, 15 Safari 5, 5.1 Opera 11.01, 11.5

It's not productive to suggest that jQuery has done some kind of "poor man's module" or that it could've done better if it had modules, or that it should, or even might be able to take advantage of some kind of bleeding edge ES.next Module system. jQuery promises that it will not break back compat from one release to the next, and when we do, we hustle to get point release bug fixes out the door. When 24.6 million[1] sites are using a piece of code - because they can trust that it works and that it won't wreak havoc on their site from one version to the next.

Rick

[1] trends.builtwith.com/javascript/jQuery

# Axel Rauschmayer (13 years ago)

I think we are arguing different points: All I meant is – how would you structure jQuery in ECMAScript.next (in the future, using the proposed modules)?

# Rick Waldron (13 years ago)

Still the same point, unified API under single namespace, for the same reasons. ES.next will still exist in the same hostile web of today.

/

# Joe Developer (13 years ago)

jQuery is a somewhat poor / extreme example - jQuery has taken a monolithic approach to code structuring - while more modern and full featured frameworks tend towards load-on-demand, and hence can offer 'capability-loading'.

That said, I do think that it is worth keeping in mind that there will continue to be a considerable lag between ES.current and ES.baseline for browser apps - when you guys introduce constructs such as |> in lieu of 'jury-riggable' approaches such as commandering Object.extend etc then it means that such code will be subject to de-facto environment lockin and running in 'less capable' environments will require maintaining separate codebases / transpile steps.

The goal may be to make JS easier - but it is more likely to have the opposite effect, code containing |> will straight up break outside of

controlled environments.

When I see things like |> and .{ I get a bit queasy, but as long as you

guys also cater for more backwards compatible constructs I guess we can all get along.

# Kam Kasravi (13 years ago)

I think most of es.next will be transpiled for a long period of time. Given Dart and Coffescript, transpilers will become more and more important and more easily incorporated into the development cycle as evidenced by Dart's recent editor announcement.

# Brendan Eich (13 years ago)

On Nov 6, 2011, at 3:29 AM, Joe Developer wrote:

jQuery is a somewhat poor / extreme example - jQuery has taken a monolithic approach to code structuring - while more modern and full featured frameworks tend towards load-on-demand, and hence can offer 'capability-loading'.

That said, I do think that it is worth keeping in mind that there will continue to be a considerable lag between ES.current and ES.baseline for browser apps - when you guys introduce constructs such as |>

It's <| for now, but may change.

in lieu of 'jury-riggable' approaches such as commandering Object.extend etc then it means that such code will be subject to de-facto environment lockin and running in 'less capable' environments will require maintaining separate codebases / transpile steps.

The goal may be to make JS easier - but it is more likely to have the opposite effect, code containing |> will straight up break outside of controlled environments.

When I see things like |> and .{ I get a bit queasy, but as long as you guys also cater for more backwards compatible constructs I guess we can all get along.

We do want APIs where possible. Sometimes there's no exact correspondence but something that is more of a companion, which can be used from non-ES6 scripts too. We have agreement to look into exposing built-in modules to unversioned script in a general fashion (e.g., Object.system is the system module loader, so Object.system.load("@name"...) gets you the private name objects built-in module).