const {resolve} = Promise; // fails

Andrea Giammarchi andrea.giammarchi at gmail.com
Fri Jul 20 00:17:07 UTC 2018


> one without precedent in the language

that's how languages move forward, right?

> It also means you can't `Promise.resolve.call(SubPromise)`

you can make it more complex and yet have a fallback to the invoker, not a
real issue, just more rules to write down.

```js
const withLazyBoundObjects = new WeakMap;
const withLazyBoundMethods = obj => {
  const descriptors = Object.getOwnPropertyDescriptors(obj);
  Object.keys(descriptors).forEach(key => {
    const desc = descriptors[key];
    const {value} = desc;
    if (desc.configurable && typeof value === 'function') {
      delete desc.value;
      delete desc.writable;
      desc.get = function () {"use strict";
        const self = this || obj;
        let methods = withLazyBoundObjects.get(self);
        if (!methods)
          withLazyBoundObjects.set(self, methods = Object.create(null));
        return methods[key] || (methods[key] = function () {
          return value.apply(this || self, arguments);
        });
      };
    }
  });
  return Object.defineProperties(obj, descriptors);
};

withLazyBoundMethods(Promise);

class SubPromise extends Promise {}

console.log([
  (0,Promise.resolve)() instanceof SubPromise,
  Promise.resolve() instanceof SubPromise,
  (0,SubPromise.resolve)() instanceof SubPromise,
  SubPromise.resolve() instanceof SubPromise,
  Promise.resolve.call(SubPromise) instanceof SubPromise
]);

// [false, false, true, true, true]
```



On Fri, Jul 20, 2018 at 1:59 AM Jordan Harband <ljharb at gmail.com> wrote:

> That's certainly a clever solution, but one without precedent in the
> language. It also means you can't `Promise.resolve.call(SubPromise)`,
> although perhaps you could avoid that by skipping `.bind` and creating a
> normal function wrapper inside the getter - I'm curious how that might be
> implemented as well as specified.
>
> On Thu, Jul 19, 2018 at 4:54 PM, Andrea Giammarchi <
> andrea.giammarchi at gmail.com> wrote:
>
>> My code doesn't suffer what Domenic says.
>>
>> Once again:
>>
>> ```js
>> const withLazyBoundObjects = new WeakMap;
>> const withLazyBoundMethods = obj => {
>>   const descriptors = Object.getOwnPropertyDescriptors(obj);
>>   Object.keys(descriptors).forEach(key => {
>>     const desc = descriptors[key];
>>     const {value} = desc;
>>     if (desc.configurable && typeof value === 'function') {
>>       delete desc.value;
>>       delete desc.writable;
>>       desc.get = function (...args) {
>>         let methods = withLazyBoundObjects.get(this || obj);
>>         if (!methods)
>>           withLazyBoundObjects.set(this, methods = Object.create(null));
>>         return methods[key] || (methods[key] = value.bind(this));
>>       };
>>     }
>>   });
>>   return Object.defineProperties(obj, descriptors);
>> };
>>
>> // patch the Promise
>> withLazyBoundMethods(Promise);
>>
>> // have a class that extends Promise
>> class SubPromise extends Promise {}
>>
>> // test inheritance
>> SubPromise.resolve() instanceof SubPromise; // true
>> (0,SubPromise.resolve)() instanceof SubPromise; // true
>>
>> // even the Promise ?
>> Promise.resolve() instanceof SubPromise; // false, it's Promise
>> (0,Promise.resolve)() instanceof SubPromise; // false, it's Promise
>> ```
>>
>> So, why cannot we have above behavior in core?
>>
>>
>>
>> On Fri, Jul 20, 2018 at 1:36 AM Jordan Harband <ljharb at gmail.com> wrote:
>>
>>> > TL;DR why aren't public static methods that need context **all**
>>> lazily defined as bound (once) on demand? That would make every single
>>> public static method consistent, accordingly with the Class you extracted
>>> them from, right? That's not clever, that's usually developers expectations
>>> because historically all public static methods don't need the Class to work.
>>>
>>> I believe
>>> https://github.com/tc39/ecma262/issues/544#issuecomment-236487230
>>> answers this - specifically, expressing that the claimed better design is
>>> for *nothing* to be bound.
>>>
>>> On Thu, Jul 19, 2018 at 4:22 PM, Andrea Giammarchi <
>>> andrea.giammarchi at gmail.com> wrote:
>>>
>>>> Reading that looks like nobody answered my question, explained through
>>>> some code that wouldn't have any issue with subclassing.
>>>>
>>>> So no, there's no answer to my latest question in there, unless I've
>>>> missed it.
>>>>
>>>> On Thu, Jul 19, 2018 at 7:56 PM Jordan Harband <ljharb at gmail.com>
>>>> wrote:
>>>>
>>>>> This question has been answered here:
>>>>> https://github.com/tc39/ecma262/issues/544
>>>>>
>>>>> On Thu, Jul 19, 2018 at 9:27 AM, Andrea Giammarchi <
>>>>> andrea.giammarchi at gmail.com> wrote:
>>>>>
>>>>>> > Per the KISS principle, let’s avoid to be clever.
>>>>>>
>>>>>> I think my next code example is less clever, but the only reason I've
>>>>>> written hacks or code was not to be advocated or adopted, just to explain
>>>>>> what could happen internally.
>>>>>>
>>>>>> TL;DR why aren't public static methods that need context **all**
>>>>>> lazily defined as bound (once) on demand? That would make every single
>>>>>> public static method consistent, accordingly with the Class you extracted
>>>>>> them from, right? That's not clever, that's usually developers expectations
>>>>>> because historically all public static methods don't need the Class to work.
>>>>>>
>>>>>> On Thu, Jul 19, 2018 at 5:23 PM Claude Pache <claude.pache at gmail.com>
>>>>>> wrote:
>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> > Le 19 juil. 2018 à 16:32, Andrea Giammarchi <
>>>>>>> andrea.giammarchi at gmail.com> a écrit :
>>>>>>> >
>>>>>>> > I know it's about subclassing, which is why I've asked why, once
>>>>>>> there's no context, the default/base one is not considered, but since
>>>>>>> everyone came back with the subclassing issue, which is actually what I've
>>>>>>> said myself on twitter about the current state, how about changing all
>>>>>>> public static methods that need it, to be getters ?
>>>>>>> >
>>>>>>> > ```js
>>>>>>> > class Promise {
>>>>>>> >   #resolve(...args) {
>>>>>>> >     return this.nativeImplementation(...args);
>>>>>>> >   }
>>>>>>> >   get resolve() {
>>>>>>> >     return #resolve.bind(this);
>>>>>>> >   }
>>>>>>> > }
>>>>>>> > ```
>>>>>>> >
>>>>>>> > we could argue `Promise.resolve === Promise.resolve` should be
>>>>>>> preserved, as behavior, so that we need a lazy defined getter ... **but**
>>>>>>> why not making public static restructuring from known constructors work
>>>>>>> regardless, under all circumstances ?
>>>>>>> >
>>>>>>>
>>>>>>> Nice hack... But it imposes all subclasses of `Promise` that
>>>>>>> override the `resolve` method to use a similar trick, because the following
>>>>>>> will break:
>>>>>>>
>>>>>>> ```js
>>>>>>> class MyPromise extends Promise {
>>>>>>>     static resolve() {
>>>>>>>         // do fancy stuff
>>>>>>>         return super.resolve()
>>>>>>>     }
>>>>>>> }
>>>>>>>
>>>>>>> const {resolve} = MyPromise
>>>>>>>
>>>>>>> resolve() // TypeError: undefined is not an object
>>>>>>> ```
>>>>>>>
>>>>>>> Per the KISS principle, let’s avoid to be clever.
>>>>>>>
>>>>>>> —Claude
>>>>>>>
>>>>>>>
>>>>>> _______________________________________________
>>>>>> 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/20180720/ac32bf1f/attachment-0001.html>


More information about the es-discuss mailing list