Why are object initializer methods not usable as constructors?

Michael J. Ryan tracker1 at gmail.com
Wed May 17 14:32:52 UTC 2017


But if you're introducing a new Class library, your writing new code... You
could almost as really setup a build chain (Babel) to support class syntax,
if you can't already target sorted browsers.


-- 
Michael J. Ryan - tracker1 at gmail.com - http://tracker1.info

Please excuse grammar errors and typos, as this message was sent from my
phone.

On May 16, 2017 4:51 PM, "/#!/JoePea" <joe at trusktr.io> wrote:

> /#!/JoePea
>
>
> On Mon, May 15, 2017 at 6:16 PM, Jordan Harband <ljharb at gmail.com> wrote:
> > 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
>
> Yeah, sure, why not? Allow library authors to do awesome things like
> provide libraries for multiple inheritance that aren't hacks.
>
> ```js
> import Bar from './Bar'
> import Baz from './Baz'
> import multiple from 'multiple-inheritance-library-by-some-author'
>
> class Foo extends multiple(Bar, Baz) {}
> ```
>
> > use `class`? That's what users who have access to ES6+ environments are
> > likely to do anyways.
>
> ES6 classes don't have protected or private members, but an author's
> `Class` tool might.
>
> Not everyone is writing ES6 in a shiny new app. There's large outdated
> code bases. It'd be convenient for a tool like `Class` to work on old
> code, and not fail on new code.
>
> >
> > It's also worth noting that someone could do `constructor: () => {}` or
> > `constructor: function *() {}` and `new`ing them would fail the same way.
>
> Yes, we can't prevent all the bad usages, but those are obviously not
> meant to work. Concise methods aren't obviously going to fail,
> especially considering that they are not really called "concise
> methods" by most people, but more like "shorthands", and by that
> terminology the layman is going to expect them to work. Arrow function
> and generatos are very explicitly different, and you have to actually
> know what they are in order to use them.
>
> There's always going to be some way to make some library fail, but
> that doesn't mean we should add more ways to make code fail when we
> can avoid it. Arrow functions and generators are necessary for a
> purpose. However, making concise methods that don't use the keyword
> `super` non-constructable doesn't really have any great purpose, it
> only makes certain code fail in needless ways...
>
> >
> > 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
> >
> >
> _______________________________________________
> 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/20170517/f9a3de6e/attachment-0001.html>


More information about the es-discuss mailing list