Promise() vs. new Promise()

Andrea Giammarchi andrea.giammarchi at gmail.com
Wed Aug 20 20:04:57 PDT 2014


For demo sake, I was talking about something like this in ES5:

```js
Object.defineProperty(
  Function.prototype,
  'new',
  {
    configurable: true,
    get: function() {
      var Constructor = this;
      Object.defineProperty(
        Constructor,
        'new',
        {
          value: function(/*...args*/) {
            // ES6: return new Constructor(…args);
            var
              o = Object.create(
                Constructor.prototype
              ),
              r = Constructor.apply(o, arguments)
            ;
            switch(typeof r) {
              case 'undefined':
              case 'boolean':
              case 'number':
              case 'string':
                return o;
              default: // including null
                return r || o;
            }
          }
        }
      );
      return Constructor.new;
    }
  }
);

// example
function A() {}

A.new() instanceof A; // true
```

Regards

P.S. please note, in case you do like above idea, some quirky engine will
fail without weird tricks on lazy reassignment.
I can write a more appropriate one if needed.



On Thu, Aug 21, 2014 at 3:30 AM, Andrea Giammarchi <
andrea.giammarchi at gmail.com> wrote:

> I like the `Function.prototype.new` hint but unless it's an implicitly
> self bound method you still cannot easily pass it around as callback
> for a map without binding it all over.
>
> `arr.map(MyClass.new)` without needing to explicitly bind it each time
> is needed/used would be an exception, but probably a good one.
>
> Regards
>
>
> Sent from my Windows Phone From: Allen Wirfs-Brock
> Sent: ‎8/‎21/‎2014 1:19
> To: brendan at mozilla.org
> Cc: es-discuss at mozilla.org
> Subject: Re: Promise() vs. new Promise()
>
> On Aug 20, 2014, at 1:11 PM, Brendan Eich wrote:
>
> > Alex Kocharin wrote:
> >> I mean, not using `new`. JS is a functional language after all, and
> having a function that can't be called as a function is weird.
> >
> > Gotcha, and my point was not to mandate `new`, just allow it. I thought
> we relaxed things so `new` was optional if there was no issue leaving it
> out:
> >
> > http://esdiscuss.org/topic/make-class-constructors-work-with-call-too
> >
> > But that was a while ago.
> >
> >> If constructor supports calling it without new, I can pass it around as
> a function, do this for example:
> >>
> >> ```
> >>> >  ['foo', 'bar'].map(Error)
> >> [ [Error: foo], [Error: bar] ]
> >> ```
> >>
> >> With mandatory `new` this would be much less elegant.
> >
> > Agreed, mandating `new` where there's no issue (legacy, e.g., Date; or
> other?) would be Bad(tm).
> >
> >> I was about to construct realistically-looking chain with [fn1, fn2,
> fn3].map(Promise).forEach(addThenHandler), but FF already seem to throw on
> it.:(
> >
> > Hrm.
>
> We've talked about this several times at TC39 meetings and the
> consensus has always been to not conflate the meaning of new C() and
> C() for new built-in constructors.
>
> The problem is that is difficult to correctly code  (in ES code) a
> constructor function that has this behavior. Even assuming there is a
> way to reliably determined if you were called  with or without `new`
> you still need to have to separate logic paths for the two cases and
> there are other subclassing issues (more below).  For these reasons,
> we should expect that most constructors defined using `class` will
> require use of  `new` to instantiate them.
>
> If as  matter of principle, we shouldn't be specifying built-ins that
> do things in a way that is difficult to reproduce in ES code and we
> shouldn't be encouraging  usage patterns  that confuse people or are
> error prone to implement.
>
> If you want a purely functional way to do instantiation, then I
> suggest adding a `new` method to Function.prototype:
> `
>    Function.prototype = function new(...args) {return new this(...args);
> `
>
> Back to subclassing, assume that Map was implemented in ES, something like
> this:
> ( **called-via-new** is a placeholder for new syntax)
> `
> class Map {
>    constructor(...args) {
>       if (! **called-via-new**) return new Map(...args);
>       // initialize this using args
>    }
>    //methods
> }
>
> //then the  following do the same thing:
> var m = Map();
> var m = new Map;
> `
> You might then,  reasonably expect to code
> `
> class ExtendedMap extends Map {
>    additionalMethod() {}
> }
> `
> but if you do, you will discover:
> `
> var m = ExtendedMap();  //actually creates an instance of Map
> var m = new ExtendedMap; //actually creates an instance of ExtendedMap;
> `
> the problem is that the Map constructor explicitly references `Map`
> rather than the actually invoked constructor and there is no good may
> to determine what the actual constructor was.  So to make the subclass
> work correctly you have to remember to code the subclass as:
> `
> class ExtendedMap extends Map {
>    constructor(...args)  {
>         if (! **called-via-new**) return new ExtendedMap(...args);
>         return new super(...args);
>    }
>    additionalMethod() {}
> }
> `
>
> and repeat a pattern like this in every other subclass you write.
> Much better to just avoid this sort ot two-faced constructors.
>
> Alen
> _______________________________________________
> 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/20140821/2b56f5e3/attachment-0001.html>


More information about the es-discuss mailing list