Why are object initializer methods not usable as constructors?

Jordan Harband ljharb at gmail.com
Tue May 16 01:16:18 UTC 2017


You seem to be suggesting that ES6 should be making it easier for you to
reimplement a core ES6 language feature. If you want `class`, can you not
use `class`? That's what users who have access to ES6+ environments are
likely to do anyways.

It's also worth noting that someone could do `constructor: () => {}` or
`constructor: function *() {}` and `new`ing them would fail the same way.

On Mon, May 15, 2017 at 5:25 PM, /#!/JoePea <joe at trusktr.io> wrote:

> > Because they're methods, not functions. The distinction between the
> > two was merely semantic in ES5, but now it's mechanical, due to
> > super(); constructing something intended as a method would make
> > super() behave in confusing and unintuitive ways, so methods just
> > don't have a constructor any more.
>
> You are correct for app authors, but wrong for library authors. A
> library author may easily like to make an object that contains ES5
> constructors, and writing them like
>
> ```
> let ctors = {
>   Foo() {},
>   Bar() {},
> }
> ```
>
> is simply simple.
>
> For example, suppose a library author releases a `Class` function for
> defining classes, it could be used like this:
>
> ```
> const Animal = Class({
>   constructor: function() {
>     console.log('new Animal')
>   }
> })
> ```
>
> but most JS authors who don't know about these pesky new JavaScript
> language internals might be inclined to write:
>
>
> ```
> const Animal = Class({
>   constructor() {
>     console.log('new Animal')
>   }
> })
> ```
>
> If the `Class` implementation returns that "constructor", then when
> the user does `new Animal` they will get an unexpected error, and that
> is not ideal at all for a dynamic language like JavaScript.
>
> What's even stranger is that the `Class` implementation can wrap the
> concise method with a [[Construct]]able function and call the concise
> method with `.call` or `.apply` and it will work! But that is simply
> just messy and ugly.
>
> So why prevent it from working only sometimes? It would be much better
> for it to just work all the time, and make restrictions only when
> `super` is present in the function body. In the above example, the
> `constructor() {}` concise method does not use the keyword `super`, so
> treating it like `constructor: function constructor() {}` would be
> much more ideal.
>
> We shouldn't limit developer creativity for reasons that don't exist
> (I haven't heard of any compelling reasons so far).
>
> The new language features cause failures in unexpected ways, and I
> really don't think the language should be designed in this
> less-intuitive way.
>
> JavaScript pre-ES6 has a dynamic nature, but ES6 and newer features
> are less-so in that tradition.
>
> > Making this one niche use-case ("I want to define several
> constructor-only classes inline in an object initializer") require a few
> characters less is not a sufficiently worthwhile benefit for the cost.
>
> Actually, no, I want to allow end-users of my library to pass in
> objects containing methods and properties, and I don't want the result
> to fail in unexpected ways, and I also don't want to write ugly and
> hacky code to make it work.
>
> > Just type the few extra characters (exactly what you would have typed in
> ES5, so it's not even a new imposition), and you'll be fine.
>
> Like I said, it won't be me typing these things, it will be end users.
> Yes I can disguise the problem, but if I for example were implementing
> a `Class` tool, I wouldn't like to wrap their non-constructable
> methods in a proxy function just to make it work not only because it
> is ugly, but because it will show things in the console that are more
> difficult to debug.
>
> For example, have you ever looked at classes made with Backbone? They
> are not so nice to inspect because Backbone wraps constructors and
> prototypes like an onion.
>
> This language "feature" of concise methods that makes them not
> constructable forces library authors to write ugly code who's output
> is harder to inspect and debug by end developers.
> /#!/JoePea
>
>
> On Sat, Jul 30, 2016 at 3:04 AM, /#!/JoePea <joe at trusktr.io> wrote:
> >>  The distinction between the two was merely semantic in ES5, but now
> it's
> >> mechanical, due to super(); constructing something intended as a method
> >> would make super() behave in confusing and unintuitive ways, so methods
> just
> >> don't have a constructor any more.
> >
> > So, if `super` were dynamic, then it would be no problem.
> >
> >> It's been explained to you already in previous threads why super() is
> >> designed the way it is, and how a dynamic super() would add significant
> cost
> >> to some situations
> >
> > Those "some situations" haven't been listed yet (or I don't know where
> they
> > are listed). Do you know any? As far as I can tell, a dynamic super would
> > perform just fine:
> >
> > - For constructor calls, `HomeObject` can just the `.prototype` property
> of
> > the function when `new.target` is the same as the function being
> > constructed. That's simple.
> > - If `new.target` is not the current constructed function, then the
> current
> > function was found on the prototype chain of
> > `Object.getPrototypeOf(new.target)` (i.e. tje `.constructor` property
> was
> > found on some `HomeObject` in the prototype chain) and then that
> function is
> > called with the found `HomeObject`. This seems like a simple addition to
> the
> > property lookup algorithm.
> > - Functions called as methods simply have `HomeObject` passed as the
> > prototype (HomeObject) where they were found. This seems like a simple
> > addition to the property lookup algorithm.
> > - What else?
> >
> > Based on those ideas from my limited knowledge on thetopic, a dynamic
> > `super` doesn't seem to "costly".
> >
> > Suppose I write
> >
> > ```js
> > obj.foo()
> > ```
> >
> > Then, in ES5, there is already going to be a property lookup algorithm to
> > find `foo` on the prototype chain of `obj`. Therefore, when the
> > property`foo` is found on a prototype (a HomeObject), it doesn't seem
> like
> > all that much extra cost to simply pass that found object by reference to
> > the `foo` method call, since we already found it. That's not very costly.
> >
> > I may be using the word "HomeObject" wrong, but I think you get what I
> mean.
> >
> >
> > /#!/JoePea
> >
> > On Thu, Jul 28, 2016 at 9:11 AM, Tab Atkins Jr. <jackalmage at gmail.com>
> > wrote:
> >>
> >> On Wed, Jul 27, 2016 at 11:44 AM, /#!/JoePea <joe at trusktr.io> wrote:
> >> > What's the good reason that object-initializer methods can't be
> >> > constructors
> >> > though? I mean, I get that "that's what spec says", but what's the
> >> > actual
> >> > good reason?
> >>
> >> Because they're methods, not functions. The distinction between the
> >> two was merely semantic in ES5, but now it's mechanical, due to
> >> super(); constructing something intended as a method would make
> >> super() behave in confusing and unintuitive ways, so methods just
> >> don't have a constructor any more.
> >>
> >> There are several very similar ways you can write your example that do
> >> achieve what you want. As Allen said, you can just use the non-concise
> >> syntax, explicitly typing "function" (or better, "class") for each of
> >> the values.  This is only a few characters more and achieves exactly
> >> what you want.
> >>
> >> It's been explained to you already in previous threads why super() is
> >> designed the way it is, and how a dynamic super() would add
> >> significant cost to some situations.  Making this one niche use-case
> >> ("I want to define several constructor-only classes inline in an
> >> object initializer") require a few characters less is not a
> >> sufficiently worthwhile benefit for the cost.  Just type the few extra
> >> characters (exactly what you would have typed in ES5, so it's not even
> >> a new imposition), and you'll be fine.
> >>
> >> ~TJ
> >
> >
> _______________________________________________
> 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/20170515/237b3026/attachment-0001.html>


More information about the es-discuss mailing list