How to fix the `class` keyword

Matthew Robb matthewwrobb at gmail.com
Wed Mar 4 18:28:45 UTC 2015


I have to be honest, there is ONE sticky point to the way classes work
right now. Why have them throw when called without `new`? The way you
traditionally guard against needing to rewrite call sites later would be to
check if this instanceof Constructor in the constructor. I believe this is
now impossible, correct?


- Matthew Robb

On Wed, Mar 4, 2015 at 12:33 PM, Dmitry Soshnikov <
dmitry.soshnikov at gmail.com> wrote:

> There is a trap one could fall into, after reading one "classic" or even
> "authoritive" book. After that it might seem one understood the essence of
> everything.
>
> For fairness, there were couple of valid points noticed:
> composition/aggregation (will be achieved, and already now can be, by
> mixins), and, probably, that you'll have to refactor call sites if you
> decide to switch to the raw factory (that's why eg Python chose to
> instantiate without 'new' keyword).
>
> Other than that, yes, factory is just a desugarred class pattern, and yes,
> sugar matters if you want to design a practical language. In case of
> class-based code reuse, prototypes were also desugarred version of it
> (that's why JS at some point was "unexplained", and as a result made it
> harder to be practical quicker). Eg in my class I give prototypes as an
> advanced topic now, since it's just an implementation detail (the same
> again as in Python, which is also delegation-based).
>
> The most valuable advice would be from Eric Arvidsson - just to design
> your language (likely, to be a "compiler" writer is easier nowadays), and
> exactly there you'll see how sugar matters.
>
> Dmitry
>
>
> On Wednesday, March 4, 2015, Eric Elliott <eric at paralleldrive.com> wrote:
>
>>
>> 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
>>
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20150304/0950635b/attachment-0001.html>


More information about the es-discuss mailing list