How to fix the `class` keyword

Eric Elliott eric at paralleldrive.com
Wed Mar 4 12:23:00 UTC 2015


I've already posted this on my Medium blog here:
https://medium.com/@_ericelliott/how-to-fix-the-es6-class-keyword-2d42bb3f4caf

It seems inevitable that the `*class*` keyword in JavaScript is going to
catch on, but that’s a problem because it’s fundamentally broken in many
ways.

Now that it’s out there and people are using it, it seems like the only
logical way forward is to *try to make it better for everybody*.

In JavaScript, *any function can instantiate and return objects.* When you
do so without a constructor, it’s called a *factory function*. The new `
*class*` syntax *can’t compete with the power and flexibility of factories*
— specifically stamps, and object pools are not the only factory use-case.

There is a whole section on object construction in the GoF “Design
Patterns” book
<http://www.amazon.com/gp/product/0201633612?ie=UTF8&camp=213733&creative=393185&creativeASIN=0201633612&linkCode=shr&tag=eejs-20&linkId=XXUP5DXMFH5VS2UI>
which
exist only to get around the limitations of constructors and classes.

See also: Three Different Kinds of Prototypal OO.
<http://ericleads.com/2013/02/fluent-javascript-three-different-kinds-of-prototypal-oo/>

The bottom line: *Class doesn’t give you any power* that isn’t already
supplied by *factory functions* and the *prototypal OO* built into the
language. All you’re doing when you create a class is opting into a *less
powerfull, less flexible mechanism* and *a whole lot of pitfalls and pain.*
<https://medium.com/javascript-scene/the-two-pillars-of-javascript-ee6f3281e7f3>

Is there any hope that the `*class*` keyword will ever be useful? *Maybe.*
Why should we bother?


Why don’t we just create a lint rule and move on?

*The `class` keyword is creating a rift* in the JavaScript community. I for
one have plans to create an ESLint config that prohibits `*class*` and
share it as far and as wide as I can — and since I’m building a community
of JavaScript developers that currently includes ~40,000 people, that’s far
enough to have an impact.

*Classes could be useful*. What if we want to build abstractions on top of
it? What if we want to do more things in the language itself that could
benefit with `*class*` integration (such as built-in *traits*)?

*We could make these changes opt-in* by adding config to the class itself.
That would prevent breaking changes and hopefully make the whole community
happy. As it stands, we're just making people with classical inheritance
backgrounds happy -- *at least until they fall into one of the many
pitfalls ahead of them.*

*Shouldn’t the entire JavaScript community benefit from `class`?*
*How to Fix `class`*

   1. *Make class inheritance compositional* similar to the way stamps are
   composed.
   <http://chimera.labs.oreilly.com/books/1234000000262/ch03.html#prototypal_inheritance_with_stamps>
In
   other words, change the behavior of `*extend*`, or *deprecate `extend`* and
   replace it with something like a *`compose` keyword* that can *compose
   any number of classes.*
   2. *Deprecate `new`. *`*new*` violates both the *substitution principle* and
   the *open / closed principle*. The `*new*` keyword is destructive
   because *it adds zero value to the language*, and it *couples all
   callers to the details of object instantiation*. If you start with a
   class that requires `*new*` (all classes in ES6) and you later decide
   you need to use a factory instead of a class, *you can’t make the change
   without refactoring all callers.* This is especially problematic for
   shared libraries and public interfaces, because *you may not have access
   to all of the code using the class.* You may think it doesn’t do any
   harm to just call a factory function with the `*new*` keyword, but the `
   *new*` keyword triggers behaviors that change what’s going on when the
   function is invoked. If you can’t count on the function to behave the same
   way for all callers, you can’t predict what the software will do. That’s
   bad.
   3. Make sure that *`class` obeys the substitution principle* when you
   switch from a class to a factory and vise verse. This is an important
   point, because if callers are counting on any behavior or property of a
   class, and you decide to change the implementation to a factory, you’ve
   just broken the calling code. Additionally, if callers are counting on the
   behavior of a factory, and you switch the implementation to a class, that’s
   similarly problematic, though as it stands, *there’s no good reason to
   switch from a factory to a class*.

The third point may be the most difficult, but if we can *catalog every
possible breaking change* here, there may be some hope for `*class*` in the
future, assuming we can get consistency baked into the language spec.

If we can’t fix these problems with `*class*`, we should push to *deprecate
the keyword entirely,* because as it exists today, *`class` is broken and
absolutely should not be used*
<https://medium.com/javascript-scene/the-two-pillars-of-javascript-ee6f3281e7f3>
*.*
Catalog of substitution breaks



   - *The behavior of `this`*. It always refers to the new instance in a
   class constructor. In a factory function, `*this*` is dynamic, and
   follows a completely different set of rules. Possible solution: *deprecate
   `this`* and instead refer to the class or function by name. A major
   drawback of this solution is that it would break `*.call()*`, `*.apply()*`
   and `*.bind()*`, unless we *also change their behavior* to override the
   function name reference.
   - *`instanceof`*- IMO, *this is broken anyway* because it doesn’t do
   what the name describes, and from a user’s perspective, *it flat out
   lies* when you try to use it across execution contexts, or when the
   constructor prototype property changes. Possible solution: *deprecate
   `instanceof`*.
   -

I know I've raised all these issues on es-discuss before and basically been
told to go suck an egg, but we all want the same thing -- *a better
JavaScript for everybody*. Being inclusive is practically baked into JS
DNA. That's how `class` found its way into JS in the first place, even
though we already had something *much better: A very good system for
prototypal OO (object literals, prototype delegation, and concatenative
inheritance via dynamic object extension).*

~ee
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150304/2ece2ddf/attachment-0001.html>


More information about the es-discuss mailing list