const {resolve} = Promise; // fails

classic Classic list List threaded Threaded
18 messages Options
Reply | Threaded
Open this post in threaded view
|

const {resolve} = Promise; // fails

Andrea Giammarchi-2
As quickly discussed on Twitter, it's very inconvenient and inconsistent that the following fails:

```js
const {resolve, reject} = Promise;

resolve(123); // throws
```

Compared to every other public static method in ECMAScript that works, including those methods that might need the contextual class, as it is for the Array.from case.

```js
const {from} = Array;

from({0: 'abc', length: 1}); // ["abc"] // all good
```

Why cannot Promise methods fallback to Promise constructor when the class/context is not available?

Wouldn't be simple/reasonable change to make so that developers expectations would be preserved?

Best Regards.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: const {resolve} = Promise; // fails

Michael Luder-Rosefield
I'd reinforce this with the fact that this works for RSVP.js https://github.com/tildeio/rsvp.js/, and so the current behaviour is a potential breaking point if code is being converted to use native Promises.

On Thu, 19 Jul 2018 at 12:56 Andrea Giammarchi <[hidden email]> wrote:
As quickly discussed on Twitter, it's very inconvenient and inconsistent that the following fails:

```js
const {resolve, reject} = Promise;

resolve(123); // throws
```

Compared to every other public static method in ECMAScript that works, including those methods that might need the contextual class, as it is for the Array.from case.

```js
const {from} = Array;

from({0: 'abc', length: 1}); // ["abc"] // all good
```

Why cannot Promise methods fallback to Promise constructor when the class/context is not available?

Wouldn't be simple/reasonable change to make so that developers expectations would be preserved?

Best Regards.
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: const {resolve} = Promise; // fails

Claude Pache
In reply to this post by Andrea Giammarchi-2


> Le 19 juil. 2018 à 13:56, Andrea Giammarchi <[hidden email]> a écrit :
>
>
> Compared to every other public static method in ECMAScript that works, including those methods that might need the contextual class, as it is for the Array.from case.
>
> ```js
> const {from} = Array;
>
> from({0: 'abc', length: 1}); // ["abc"] // all good
> ```

That pattern falls apart when subclassing:

```js
class ImprovedArray extends Array {
        /* implementation NOT overriding the `from` static method  */
}

const {from} = ImprovedArray

from({0: 'abc', length: 1}) // Array instance instead of ImprovedArray instance
```

So, no, the `Array.from` precedent is a bad one.

—Claude

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: const {resolve} = Promise; // fails

T.J. Crowder-2
In reply to this post by Andrea Giammarchi-2
On Thu, Jul 19, 2018 at 12:56 PM, Andrea Giammarchi
<[hidden email]> wrote:
> Why cannot Promise methods fallback to Promise constructor when the
> class/context is not available?

That sounds reasonable on first glance, but I'd be concerned about what happens when you do it after subclassing:

```js
class MyPromise extends Promise {
    // ...and adds some important feature...
}
// ...
const {resolve, reject} = MyPromise;
const p = resolve();
p.someImportantFeature(/*...*/); // TypeError: undefined is not a function
```

...since `resolve` fell back to `Promise`. That feels like a footgun. Either subclassers would have to handle that, which they will forget to do, or it has to be a bit more complicated than just a simple fallback to `Promise` (I don't immediately know what that "more complicated" answer would be.)

-- T.J. Crowder


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: const {resolve} = Promise; // fails

Andrea Giammarchi-2
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 ?


On Thu, Jul 19, 2018 at 4:11 PM T.J. Crowder <[hidden email]> wrote:
On Thu, Jul 19, 2018 at 12:56 PM, Andrea Giammarchi
<[hidden email]> wrote:
> Why cannot Promise methods fallback to Promise constructor when the
> class/context is not available?

That sounds reasonable on first glance, but I'd be concerned about what happens when you do it after subclassing:

```js
class MyPromise extends Promise {
    // ...and adds some important feature...
}
// ...
const {resolve, reject} = MyPromise;
const p = resolve();
p.someImportantFeature(/*...*/); // TypeError: undefined is not a function
```

...since `resolve` fell back to `Promise`. That feels like a footgun. Either subclassers would have to handle that, which they will forget to do, or it has to be a bit more complicated than just a simple fallback to `Promise` (I don't immediately know what that "more complicated" answer would be.)

-- T.J. Crowder


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: const {resolve} = Promise; // fails

Andrea Giammarchi-2
sorry, that'd be `public get resolve()` and also `public #resolve()` so nobody should be confused about the fact I'm talking about public static methods.

On Thu, Jul 19, 2018 at 4:32 PM Andrea Giammarchi <[hidden email]> wrote:
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 ?


On Thu, Jul 19, 2018 at 4:11 PM T.J. Crowder <[hidden email]> wrote:
On Thu, Jul 19, 2018 at 12:56 PM, Andrea Giammarchi
<[hidden email]> wrote:
> Why cannot Promise methods fallback to Promise constructor when the
> class/context is not available?

That sounds reasonable on first glance, but I'd be concerned about what happens when you do it after subclassing:

```js
class MyPromise extends Promise {
    // ...and adds some important feature...
}
// ...
const {resolve, reject} = MyPromise;
const p = resolve();
p.someImportantFeature(/*...*/); // TypeError: undefined is not a function
```

...since `resolve` fell back to `Promise`. That feels like a footgun. Either subclassers would have to handle that, which they will forget to do, or it has to be a bit more complicated than just a simple fallback to `Promise` (I don't immediately know what that "more complicated" answer would be.)

-- T.J. Crowder


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: const {resolve} = Promise; // fails

Andrea Giammarchi-2
I guess one example would be more explicative: why cannot public static methods be defined in a similar manner?

```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);
};

// example
const {resolve, reject} = withLazyBoundMethods(Promise);
resolve(123).then(console.log);
```

On Thu, Jul 19, 2018 at 4:33 PM Andrea Giammarchi <[hidden email]> wrote:
sorry, that'd be `public get resolve()` and also `public #resolve()` so nobody should be confused about the fact I'm talking about public static methods.

On Thu, Jul 19, 2018 at 4:32 PM Andrea Giammarchi <[hidden email]> wrote:
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 ?


On Thu, Jul 19, 2018 at 4:11 PM T.J. Crowder <[hidden email]> wrote:
On Thu, Jul 19, 2018 at 12:56 PM, Andrea Giammarchi
<[hidden email]> wrote:
> Why cannot Promise methods fallback to Promise constructor when the
> class/context is not available?

That sounds reasonable on first glance, but I'd be concerned about what happens when you do it after subclassing:

```js
class MyPromise extends Promise {
    // ...and adds some important feature...
}
// ...
const {resolve, reject} = MyPromise;
const p = resolve();
p.someImportantFeature(/*...*/); // TypeError: undefined is not a function
```

...since `resolve` fell back to `Promise`. That feels like a footgun. Either subclassers would have to handle that, which they will forget to do, or it has to be a bit more complicated than just a simple fallback to `Promise` (I don't immediately know what that "more complicated" answer would be.)

-- T.J. Crowder


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: const {resolve} = Promise; // fails

Michael Luder-Rosefield
At this point I can't ignore how much overlap there is between this and the this-binding operator proposal https://github.com/tc39/proposal-bind-operator

```
const resolve = ::Promise.resolve; // takes and binds
```

As someone who often extracts functions with deconstruction, I'd love for there to be an extension to this proposal to handle this case.

```
const { resolve, reject } = ::Promise; // ?
```

That would leave the question though of what to do with nesting:

```
const { fn1, foo: { fn2 } } = ::bar; // fn1 is bound to bar. Is fn2 bound to bar, or foo?
```

On Thu, 19 Jul 2018 at 15:58 Andrea Giammarchi <[hidden email]> wrote:
I guess one example would be more explicative: why cannot public static methods be defined in a similar manner?

```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);
};

// example
const {resolve, reject} = withLazyBoundMethods(Promise);
resolve(123).then(console.log);
```

On Thu, Jul 19, 2018 at 4:33 PM Andrea Giammarchi <[hidden email]> wrote:
sorry, that'd be `public get resolve()` and also `public #resolve()` so nobody should be confused about the fact I'm talking about public static methods.

On Thu, Jul 19, 2018 at 4:32 PM Andrea Giammarchi <[hidden email]> wrote:
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 ?


On Thu, Jul 19, 2018 at 4:11 PM T.J. Crowder <[hidden email]> wrote:
On Thu, Jul 19, 2018 at 12:56 PM, Andrea Giammarchi
<[hidden email]> wrote:
> Why cannot Promise methods fallback to Promise constructor when the
> class/context is not available?

That sounds reasonable on first glance, but I'd be concerned about what happens when you do it after subclassing:

```js
class MyPromise extends Promise {
    // ...and adds some important feature...
}
// ...
const {resolve, reject} = MyPromise;
const p = resolve();
p.someImportantFeature(/*...*/); // TypeError: undefined is not a function
```

...since `resolve` fell back to `Promise`. That feels like a footgun. Either subclassers would have to handle that, which they will forget to do, or it has to be a bit more complicated than just a simple fallback to `Promise` (I don't immediately know what that "more complicated" answer would be.)

-- T.J. Crowder

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: const {resolve} = Promise; // fails

Claude Pache
In reply to this post by Andrea Giammarchi-2


> Le 19 juil. 2018 à 16:32, Andrea Giammarchi <[hidden email]> 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: const {resolve} = Promise; // fails

Andrea Giammarchi-2
In reply to this post by Michael Luder-Rosefield
Yes Michael, the `::` operator is the best thing ever proposed and got killed / pseudo replaced by another, completely different, operator that won't solve problems `::` would: the `|>` pipe one.

I'm a big fan of the `::` operator, and if it were there, I would quite possibly also like the "per context" restructuring.



On Thu, Jul 19, 2018 at 5:12 PM Michael Luder-Rosefield <[hidden email]> wrote:
At this point I can't ignore how much overlap there is between this and the this-binding operator proposal https://github.com/tc39/proposal-bind-operator

```
const resolve = ::Promise.resolve; // takes and binds
```

As someone who often extracts functions with deconstruction, I'd love for there to be an extension to this proposal to handle this case.

```
const { resolve, reject } = ::Promise; // ?
```

That would leave the question though of what to do with nesting:

```
const { fn1, foo: { fn2 } } = ::bar; // fn1 is bound to bar. Is fn2 bound to bar, or foo?
```

On Thu, 19 Jul 2018 at 15:58 Andrea Giammarchi <[hidden email]> wrote:
I guess one example would be more explicative: why cannot public static methods be defined in a similar manner?

```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);
};

// example
const {resolve, reject} = withLazyBoundMethods(Promise);
resolve(123).then(console.log);
```

On Thu, Jul 19, 2018 at 4:33 PM Andrea Giammarchi <[hidden email]> wrote:
sorry, that'd be `public get resolve()` and also `public #resolve()` so nobody should be confused about the fact I'm talking about public static methods.

On Thu, Jul 19, 2018 at 4:32 PM Andrea Giammarchi <[hidden email]> wrote:
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 ?


On Thu, Jul 19, 2018 at 4:11 PM T.J. Crowder <[hidden email]> wrote:
On Thu, Jul 19, 2018 at 12:56 PM, Andrea Giammarchi
<[hidden email]> wrote:
> Why cannot Promise methods fallback to Promise constructor when the
> class/context is not available?

That sounds reasonable on first glance, but I'd be concerned about what happens when you do it after subclassing:

```js
class MyPromise extends Promise {
    // ...and adds some important feature...
}
// ...
const {resolve, reject} = MyPromise;
const p = resolve();
p.someImportantFeature(/*...*/); // TypeError: undefined is not a function
```

...since `resolve` fell back to `Promise`. That feels like a footgun. Either subclassers would have to handle that, which they will forget to do, or it has to be a bit more complicated than just a simple fallback to `Promise` (I don't immediately know what that "more complicated" answer would be.)

-- T.J. Crowder

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: const {resolve} = Promise; // fails

Andrea Giammarchi-2
In reply to this post by Claude Pache
> 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 <[hidden email]> wrote:


> Le 19 juil. 2018 à 16:32, Andrea Giammarchi <[hidden email]> 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: const {resolve} = Promise; // fails

Jordan Harband
This question has been answered here: https://github.com/tc39/ecma262/issues/544

On Thu, Jul 19, 2018 at 9:27 AM, Andrea Giammarchi <[hidden email]> 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 <[hidden email]> wrote:


> Le 19 juil. 2018 à 16:32, Andrea Giammarchi <[hidden email]> 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: const {resolve} = Promise; // fails

Andrea Giammarchi-2
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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> wrote:


> Le 19 juil. 2018 à 16:32, Andrea Giammarchi <[hidden email]> 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: const {resolve} = Promise; // fails

Jordan Harband
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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> wrote:


> Le 19 juil. 2018 à 16:32, Andrea Giammarchi <[hidden email]> 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: const {resolve} = Promise; // fails

Andrea Giammarchi-2
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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> wrote:


> Le 19 juil. 2018 à 16:32, Andrea Giammarchi <[hidden email]> 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: const {resolve} = Promise; // fails

Jordan Harband
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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> wrote:


> Le 19 juil. 2018 à 16:32, Andrea Giammarchi <[hidden email]> 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss





_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: const {resolve} = Promise; // fails

Andrea Giammarchi-2
> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> wrote:


> Le 19 juil. 2018 à 16:32, Andrea Giammarchi <[hidden email]> 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss





_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: const {resolve} = Promise; // fails

Andrea Giammarchi-2
FYI, in case anyone is interested on my user-land solution, there is a (dual) module now, and it's called `self-aware` [1]

It's a slightly revisited, 100% code covered, generic method "patcher" to fix Promise and/or others.

Best Regards


On Fri, Jul 20, 2018 at 2:17 AM Andrea Giammarchi <[hidden email]> wrote:
> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> 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 <[hidden email]> wrote:


> Le 19 juil. 2018 à 16:32, Andrea Giammarchi <[hidden email]> 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
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss





_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss