Infrequently Noted

Alex Russell on browsers, standards, and the process of progress.

Comments for Class Warfare


+1 on the Max/Min classes.

I don't think its sustainable for everyone to send +1/-1 to the es-discuss mailing list.

Amjad: Good thinking = )

Updated to suggest that folks comment here instead.

by alex at
Agreed, max/min seems like the right solution. One way or another, we need *something* to make inheritance simpler. And to make it easier to exchange code between various frameworks (where almost each one has its own inheritance API).

I think the anti-argument is also about non-extensibility. Without a declarative syntax, it is presumably more difficult to enable it. Non-extensible instances would be great (preventing typos), but are tricky as soon as there is subtyping. But I agree with you, I don’t see how that couldn’t be added later. Furthermore, the max/min syntax is good as it is, I wouldn’t want it to be declarative.

> ... short-term stack space in our wetware ...

First, please don't talk like that. Second, if you are keeping the JS way of doing objects (prototypes, etc) in short-term memory, you are doing it wrong.

by Craig Ewert at
I've been writing NodeJS apps with Traceur and Max/Min classes.

Personally I don't care about prototypes vs classical or any stuff related or around them. As long as I get clean, concise and elegant way to build types/units that encapsulate code and logic, and I can have my inheritance and traits without learning a custom approach taken by every single JS application and library out there, then I will be happy.

by Kai Sellgren at
Marco:

On browser population, trust me; I feel your pain. It's the reason I've spent years of my life trying to provide us all with a workaround in the form of Chrome Frame. I get that none of this stuff really matters until we can fix the decay rate of Old IE, and I'm still working to make that better. But we can't just do nothing while we wait for the cavalry to arrive, else we'll be empty handed when it does get better and have nothing to show for our hard-won victory.

by alex at
Pardon me, but can't you already textbook 'class' using Resig's thing? It's a ridiculously small piece of code to include in one's utils and works to enforce all the stuff you don't really need to be doing but are most comfortable looking at.

http://ejohn.org/blog/simple-javascript-inheritance/

by DvD at
Either TC39 needs to appoint some Hixon-esque benevolent dictator to decide these things, or the whole committee should be locked into a room until they reach agreement on classes and a lambda syntax. Otherwise, I don't have any hope that consensus will ever be reached, and we might as well all just switch to CoffeeScript.
by Jon Rimmer at
I don't get why adding classes to the spec is even up for discussion. Call me a JS purist, but I came from a classical background, OOP to the core. Switching to the prototypical paradigm was like putting mayonnaise on my peanut butter & jelly. It tasted bad; I hated taking bites and I just wanted nothing to do with it.

I realized, maybe if I have to deal with mayonnaise, why not just try making an equally tasty sandwich with the new ingredient?

"Don’t add classes and the world at large thinks of JS as a joke and a toy" -- so because we have a "new generation" of classically-trained programmers who are using Javascript we need to add a "class" keyword so they don't feel so weird about prototyping? I'm one of those programmers. I got over it, so can they.

The ECMAScript 5 spec addressed A LOT of the issues I have personally with prototyping. I cannot wait until its adopted across the board.

I think creations like Coffeescript (and dare I even say Dart) have put the web app development world in a frenzy over shimming every classical OOP pattern into Javascript (or in the case of Dart, dropping JS altogether). I think this post highlights a critical fork in the road.

by Mark at
very well said.

plato thought of classes first (theory of forms), darwin has classified them (origin of species) and since then, we know humans are mammals. and i don't hear any debate about that in science community.

i think, just like you said, dismissing the idea of classes is ... uhm .. dumb. (except how Rob Pike thinks about them in Go)

thanks to jeremy/coffeescript, we don't participate in this debate. And developing happily in JS.

by devrim at
Consider me anti-classes. What happens in this scenario?

class Foo { uno: [] }

class Bar extends Foo {

}

var a = new Foo(); var b = new Bar();

b.uno.push('oops!');

In regular old JavaScript Foo is the prototype of Bar, so uno is a shared object for all instances of Foo (including all instances of Bar). Learning this is one of the hardest parts of learning JavaScript and prototypical inheritance. The prototype is shared, this has to be learned.

So what does the class keyword say about this? Are object literals in the class not shared (and therefore JavaScript loses some of it's elegance)? Or are they shared and you just have to know that?

If it's the latter, I'm afraid we're going to confuse new programmers even more. When you see the class keyword you expect it towork more or less like classes work in Java, Python, Ruby, C#, and every other OO language with classes. In JavaScript inheritance is more like inheriting only the "static" properties of the parent object (to make a Java comparison).

Didn't we add Object.create to get away from the idea of "instances" and simply the language to just being about objects?

My opinion is we just need a better Object.create. Add multiple inheritance (via an array of parent objects). Get rid of the property descriptor parameter (that's a feature you only need a small percentage of the time) and replace it with a normal object literal. Those 2 things alone would make working with objects much simpler than they are today (and it's already much simpler than it used to be).

by Matthew at
Hi Matthew:

So there aren't data properties on Max/Min class bodies. All data initialization must happen in the ctor. This is one of their key virtues and something I've lobbied hard for in any class proposal: either you need a pre-constructor phase that initializes all data on the instance before you enter the construtor, or you can't have prototype-level data properties. Max/Min classes goes the second route.

So your fatal flaw simply isn't.

As for Object.create(), I like me some composition too, but as soon as you have a delegation system + an initializer (which you'll want, trust me), you have classes. So can we stop pretending we don't have them and/or won't need them already?

Regards

by alex at
I've seen way too many big apps suffer greatly from the lack of proper class declaration in JS. Arguing about silly stuff while crowds of developers have to write millions of lines of boilerplate code is a sad thing to see.

The max/min proposal looks usable enough that it would alleviate the current pains awhile providing a base for future extension.

Just get it done please!

Max/min classes seem like the right way forward. It seems to me though that the problem is not around classes themselves but more around a lack of ability to properly resolve disputes/disagreements.

I get that a BDFL style approach to solving that is unlikely to work in JS, but maybe something like the Zen of Python might be a good idea - I.e. something that everyone agrees with and that people can point at to help them decide on the right approach and whether particular features are a good/worthwhile thing or not.

alex: Wonderful news, knowing that makes the proposal much more palatable for me, I could possibly get behind it. I would strongly recommend the placement of objects in the class body to be a parse time error. I feel this is a common but also overlooked mistake that people coming from other OO languages make.

In some regards the battle over classes is the struggle between JavaScript's dual functional/OO nature, something that it has always strandled better than most other languages. The C word raises concerns (with myself, I will admit) that the OO faction is gaining greater control over the language (with heavy migration into JS from developers with heavy OO backgrounds).

by Matthew at
Modules are the way to go for javascript: the complexity/enterprise argument is wrong. A module is less complex than a class, inheritance sucks, and just because someone was taught OO it does not make it more enterprise, or a better paradigm.

When classes are added to JS, engines will optimize for classes, and performance will degrade using plain old functions. You can disagree, but you know this is in highly likely. Engineers will optimize for the most common case, and evangelize classes. Imho Vendors are pushing for classes, not JS devs.

There's a reason people love javascript. There are many faults. Lack of classes is not one of them.

Ignoring a large portion of developers who love javascript is not a good idea. I won't use classes. But it's worse than that, it's fixing something that is not broken and taking the language in a direction developers do not appreciate

e.g. of useful stuff that need fixing: overloading functions would be awesome

by Nuno at
One of the premises of this argument is the concept, "...all we must do to save the language is teach people the zen of function objects and closures and all will be well with the world…and if we lose some people, so what," is not entirely accurate.

First off, "save the language"? Last I looked JavaScript usage and adoption was absolutely exploding. I don't think it needs to be saved.

Secondly, I would contend that we (whomever "we" are) are not losing anyone. Are developers who learn JS "lost" to Java development, or C++?

I would certainly think not.

Software developers are constantly learning new languages and language syntaxes, and while OO is certainly the predominant theory taught in many schools and universities, it's by no means the only one. Also, the current new generation of developers are not being indoctrinated into OO because of the dominance of web apps and mobile development.

Implementing and supporting classes in JS would be a step backwards, not a step forwards - even if it would change the language's perception among the established development community (which I doubt it would since the perception is extremely hard to change after all this time).

If classes are implemented tomorrow, there isn't going to be this massive rush from development shops all over the world to start using JavaScript.

It will take time.

I make the argument that in the time it takes for the paradigm shift to occur with seasoned developers to use JS because it supports classes, the next generation of developers will BECOME the seasoned developers who already know how to proficiently develop with functions as first class citizens.

I guess I simply don't understand the need to implement a feature that corrupts the very nature of the language that makes it unique, powerful and more flexible simply because some folks don't, or won't, take the time to learn the language in the first place.

by Steve at
Hi Steve,

I think you've missed critical points in the debate. I'm not suggesting people should cargo-cult their OO preconceptions. That, thankfully, is a battle that I and others who like JS just fine (thank you very much) have fortunately won. Classes as proposed are mere sugar over an oft-repeated pattern which is absolutely JS-native. No Java here. See my previous post on the topic to help clear up your misapprehensions: http://infrequently.org/2011/09/why-class-doesnt-mean-what-you-think-it-means/

The rest of your arguments are based on the faulty premises you brought with you to the comments about what's being proposed and I won't beat this D.O.A. horse. Luckily, the classpocalypse you envision is the furthest thing from what will happen when we get classes, and the debate now is if we can keep the last vestiges of static-language thinking from blocking the progress we are overdue for in the language.

Regards

by alex at
Hi Alex,

you said: "All data initialization must happen in the ctor. This is one of their key virtues and something I’ve lobbied hard for in any class proposal: either you need a pre-constructor phase that initializes all data on the instance before you enter the construtor, or you can’t have prototype-level data properties. Max/Min classes goes the second route."

I'm not versed in the intricacies of all of this, but I don't understand that entirely. If I read the proposal correctly, then prototype-level data ("class data") can be defined, just outside of the class block itself.

class Foo { ... }; Foo.uno = [];

As a tangent, I think that striving for the minimum is better than doing more. I worry about rampant use of getters and setters, for example. I understand their utility (and sometimes fantastic utility) but I'm disposed to understanding the approximate cost of a line of code by looking at it. Get/setters (and other operator overloading) take something that looks atomic, simple, and safe (like an assignment or addition) and potentially makes it giant, scary, and slow. I like the code to express this cost in some way (e.g. by having it look like a function call).

by Shannon at
@alex from developer standpoint - it still sounds like cargo cult. Inheritance is very important in Java, where you cannot (afaik?) mixin or borrow methods. And not particularly needed in JS.

p.s.: from manager standpoint, classes are very good as they can ease up life of transpilers and numerous java / c# programmers, who cannot to be bothered to learn js (or cough anything new ).

sorry, if i am wrong.


What benefits Classes have over normal objects ? Private properties/methods aka "variables-in-closure" ? Why not add ability to mark ANY object properties as private ? This will help language much more than adding classes

var q = { private secret: 42, answer () -> { return this.secret; }; }; q.secret; // undefined var z = Object.extend(q,{ answer () -> { return this.secret * 2; }; }); z.answer(); //84

by c69 at
Shannon:

What you've done in that example is to add a new data property to the function object which is named by the class, not it's prototype. In other languages, that's a "static" data property. In the proposal you could still do crazy stuff like:

class Foo { … }; Foo.prototype.uno = [];

But then you're asking for whatever trouble you get.

by alex at
Alex, I appreciate your thoughts here. The new Maximally Minimal Classes proposal does strike me as being "just sugar". I'm still not sure I agree with all of your points, but maybe we can have that conversation next time we meet in person.

But I would like to throw this into the discussion. What I've been arguing lately about es.next proposals is that they may be adding wins to the language, but they are also adding complexity and confusion. See my post about fat arrow and the ensuing discussion (would love to have your thoughts there as well).

The problem with something like classes is that while it follows all the basic rules of js, it presents them in a new syntax that creates dissonance. So a class has to desugar to a function with prototype methods. So the constructor inside it is a different construct? Does the prototype live on the class or on the constructor? If I get an instance from this class, can people mess with that instance or can I count on it always being what it's supposed to be? I know the answer to these questions, but I argue that they are not obvious to someone learning the language. They are not obvious to someone coming from another language with a stricter definition of how classes behave. That's why I can sympathize with the argument from your colleague.

The question is, if we don't expect people to be able to build a working mental model of these constructs and reason about them sufficiently, then what is their purpose? If we introduce a class that falls all over the traditional prototypal usage and also falls all over the OO mindset that some are almost certainly going to come into this with, where is the win? How is it not just another point of confusion.

My example of this is the concept of dynamic this. It's close enough to OO to seem familiar, and then it has this wildly different behavior that people are still tripping over decades later. I don't know what the pitfalls will be of these class proposals. But I calling them classes at all is just asking for trouble. I don't have another name that might help to disambiguate. At least "module" is sufficiently generalized and doesn't come with baggage.

Not sure if I've been clear here, but those are my thoughts. In the end I agree that we need consensus more than perfection.

by Marco Rogers at
Sorry, here's the link to my fat arrow post. It's actually less about fat arrow and more about what criteria we are using to evaluate proposals. https://gist.github.com/2364818
by Marco Rogers at
Constantine -- classes and data hiding are orthogonal (see Smalltalk, etc.).

Everybody -- even having a bleh syntax for classic OO classes, even if it's just sugar, is a win in that we don't have to ship a convenience function down the wire, and classes from multiple sources can interoperate. Think of it as "querySelectorAll" for object designs.

Whoops! Duh. Sorry about the missing .prototype. That was a typo.

A not-crazy example might be what amounts to an enum.

class Color { ... } Color.prototype.WHITE = 0xffffff; Color.prototype.RED = 0xff0000; Colo.blend(Color.WHITE, 0xff00ff, .5);

I've also used class variables for caches and the ilk as well.

I'm perfectly happy declaring them in foo.prototype.blah form (as opposed to within the class block). I was confused because your comment seemed to indicate that one wasn't able to have prototype level data.

by Shannon at
I think that Python is an excellent example of prototypal object orientation, and it works great. Much like in Javascript, everything in Python is a dict, including classes and their instances. Occasionally newbies will get tripped up when mutating an object in the class dict when they meant for the change to be local to an instance, but aside from that classes are very easy to use. It's a familiar pattern that's good at expressing certain ideas — and that's all it needs to be.

With javascript, any new framework you look at will have its own way of defining something like a class. They're trivially different and they haven't really evolved at all in the past few years. This makes them ripe for standardization IMO.

My only concern is that the underlying prototype still be exposed to those who know what they're doing. Also, classes should be mutable by default, just like everything in JS, but I guess if people want to "freeze" objects that should be easy enough too. Overall, the maximally minimal classes proposal seems to capture all the right behaviour pretty cleanly. +1

by Nathan Wright at
Hey Marco:

I'd be on-side with you if we didn't have enormous piles of evidence to suggest that people are already staring down the complexity you're accusing us of adding, but doing it in an ad-hoc, non-interoperable way. Nearly every JS library includes some form of class system (yes, even jQuery via jQuery UI). If we weren't simply codifying something you demonstrably need, I think your critique would be more relevant; but as it stands, we're overdue for this. The complexity exists, people are already struggling with it, and there's an opportunity for the language to do something reasonable to help settle the various style/pattern/library wars around classes.

I have some sympathy for the idea that we should use a name other than "class", but doing that would prevent us from introducing them in non-module or opt-in environments and would make whatever the alternative keyword is contextual. That's going to force developers to know that they can only use these newfangled object factories in some contexts but not others, adding mental overhead.

by alex at
Shannon:

Your example still doesn't work. The Color function object (aka "class") delegates to something other than Color.prototype. In this case, that something is Function.prototype. That means that you can't de-reference Color.WHITE unless you add it to the function object directly (as you did above) as a "static". That's allowed.

What adding things to Color.prototype.* does is make them available as things you can de-reference on instances of Color. Here's a quick example showing what works:

class Color { constructor() { ... } }
// Class-level data (aka, "statics")
Color.WHITE = 0xffffff;
Color.blend = function(c1, c2, alpha) { ... };

// Prototypal method
Color.prototype.blend = function(other, alpha) {
  return Color.blend(this, other, alpha);
};

// Now, usage:
let c1 = new Color(...);
let c2 = new Color(...);
let b1 = Color.blend(c1, Color.WHITE, 0.5);
let b2 = c2.blendWith(c1, 0.5);

Does that clear it up?

by alex at
I like the proposal, but one thing strikes me as strange --- explicit super calls in constructors. While it is flexible, it is extremely error prone, refactor-unfriendly, and violates an object invariant potentially. Realistically how many cases, when you want to skip super's constructors vs. cases when you don't? Obviously if it is the best we can have, it is better than nothing
Alex, yes it does! Thanks for your patience!
by Shannon at
After reading the proposal I still think this might not be enough to really make a difference. The biggest pain in the butt part of OO in javascript is loosing the this pointer when using function references. So we have to proxy the methods every time we want to hand out a reference and maintain the this pointer. I think without fixing that adding classes won't have as much impact to improved productivity because the competition, coffeescript and Dart, offers this already. If you look at the feature list on coffeescript its disheartening the state of javascript. This is happening one way or another the debate is will it be in javascript or other languages that transpile to javascript. If TC39 kicks the can down the road for another 5 years they'll have to contend with the rising languages that will be working from a stronger position.
Alex:

I don't doubt what you're saying. I just doubt that adding a "recommended" version of classes is going to solve it. These various class libs all do things differently because that's how their authors want to solve the problem. And through conflict and fear of backwards incompatibility, we've ensured that class syntax can be ignored, extended or co-opted for the same nefarious purposes. I think there will be some adoption of the class syntax and some reduction of ad-hoc solutions. But as long as it doesn't do what some people expect, javascript is still flexible enough for people to do their own thing.

All that being said. This may still be good enough. More important than anything is making it possible for devs to adopt the new syntax sooner rather than later. That story is getting better for browser apis, but not so much for js upgrades. New js syntax is still just not feasible for the wide majority of browser devs. This may seem like a lame argument, but it has consequences in trying to gain support for this stuff. What it means is that the support you might otherwise get isn't there because most practical devs just don't care. Because they know it won't make a difference for them for a while yet.