Darien Valentine (2018-07-24T02:24:01.000Z)
> That, and that the existing builtins already impose those limitations -
and only class allows you to do those things, with them.

I’m surprised by that statement — it appeared to me that it currently
remains possible to create classes, including classes that extend
built-ins, with class syntax.

```
const test = value => {
  if (typeof value !== 'string') throw new TypeError('nope');
  return value;
};

function StringSet(init) {
  if (new.target === undefined)
    throw new TypeError('StringSet is not a constructor');
  if (init !== undefined)
    init = Array.from(init, test);

  return Reflect.construct(Set, [ init ], new.target);
}

Reflect.defineProperty(StringSet.prototype, 'add', {
  configurable: true,
  value: Object.setPrototypeOf({
    add(value) {
      return super.add(test(value));
    }
  }, Set.prototype).add
});

Reflect.defineProperty(StringSet.prototype, Symbol.toStringTag, {
  configurable: true,
  value: 'StringSet'
});

Reflect.setPrototypeOf(StringSet, Set);
Reflect.setPrototypeOf(StringSet.prototype, Set.prototype);

new StringSet('abc');
```

Not that this is something one is apt to want to do normally, though it
being possible does remain useful sometimes for meta/compositiony stuff. It
cannot be achieved in an <= ES5 environment, but it seems all the
reflection tools needed are present in environments that actually have
class syntax — even, despite the awkwardness necessitated by HomeObject
stuff, what is needed to employ super in methods.

I’m curious if, aside from the possibility of implementation-specific
things like type error messages being different, there there is anything
about the above class which ends up observably different from the ES-side
from one created with class syntax instead?
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180723/45ab7c61/attachment.html>
valentinium at gmail.com (2018-07-24T02:40:30.560Z)
> That, and that the existing builtins already impose those limitations - and only class allows you to do those things, with them.

I’m surprised by that statement — it appeared to me that it currently remains possible to create classes, including classes that extend built-ins, without class syntax.

```
const test = value => {
  if (typeof value !== 'string') throw new TypeError('nope');
  return value;
};

function StringSet(init) {
  if (new.target === undefined)
    throw new TypeError('StringSet is not a constructor');
  if (init !== undefined)
    init = Array.from(init, test);

  return Reflect.construct(Set, [ init ], new.target);
}

Reflect.defineProperty(StringSet.prototype, 'add', {
  configurable: true,
  value: Object.setPrototypeOf({
    add(value) {
      return super.add(test(value));
    }
  }, Set.prototype).add
});

Reflect.defineProperty(StringSet.prototype, Symbol.toStringTag, {
  configurable: true,
  value: 'StringSet'
});

Reflect.setPrototypeOf(StringSet, Set);
Reflect.setPrototypeOf(StringSet.prototype, Set.prototype);

new StringSet('abc');
```

Not that this is something one is apt to want to do normally, though it
being possible does remain useful sometimes for meta/compositiony stuff. It
cannot be achieved in an <= ES5 environment, but it seems all the
reflection tools needed are present in environments that actually have
class syntax — even, despite the awkwardness necessitated by HomeObject
stuff, what is needed to employ super in methods.

I’m curious if, aside from the possibility of implementation-specific
things like type error messages being different, there there is anything
about the above class which ends up observably different from the ES-side
from one created with class syntax instead?

---

Edit: I can think of one. Because of how the home object’s prototype has been set for `add` here, reassigning the prototype of `StringSet.prototype` will not affect the super reference resolution as it would in a class-syntax class. This can be very awkwardly addressed too, though:

```

Reflect.defineProperty(StringSet.prototype, 'add', {
  configurable: true,
  value: {
    add(value) {
      return Reflect.getPrototypeOf(Reflect.getPrototypeOf(this)).add.call(this, test(value));
    }
  }.add
});
```

(To clarify I’m not obv not suggesting this is better than `class StringSet extends Set { ... }`, just want to understand what can’t presently be done other ways.)
valentinium at gmail.com (2018-07-24T02:39:43.615Z)
> That, and that the existing builtins already impose those limitations - and only class allows you to do those things, with them.

I’m surprised by that statement — it appeared to me that it currently
remains possible to create classes, including classes that extend
built-ins, with class syntax.

```
const test = value => {
  if (typeof value !== 'string') throw new TypeError('nope');
  return value;
};

function StringSet(init) {
  if (new.target === undefined)
    throw new TypeError('StringSet is not a constructor');
  if (init !== undefined)
    init = Array.from(init, test);

  return Reflect.construct(Set, [ init ], new.target);
}

Reflect.defineProperty(StringSet.prototype, 'add', {
  configurable: true,
  value: Object.setPrototypeOf({
    add(value) {
      return super.add(test(value));
    }
  }, Set.prototype).add
});

Reflect.defineProperty(StringSet.prototype, Symbol.toStringTag, {
  configurable: true,
  value: 'StringSet'
});

Reflect.setPrototypeOf(StringSet, Set);
Reflect.setPrototypeOf(StringSet.prototype, Set.prototype);

new StringSet('abc');
```

Not that this is something one is apt to want to do normally, though it
being possible does remain useful sometimes for meta/compositiony stuff. It
cannot be achieved in an <= ES5 environment, but it seems all the
reflection tools needed are present in environments that actually have
class syntax — even, despite the awkwardness necessitated by HomeObject
stuff, what is needed to employ super in methods.

I’m curious if, aside from the possibility of implementation-specific
things like type error messages being different, there there is anything
about the above class which ends up observably different from the ES-side
from one created with class syntax instead?

---

Edit: I can think of one. Because of how the home object’s prototype has been set for `add` here, reassigning the prototype of `StringSet.prototype` will not affect the super reference resolution as it would in a class-syntax class. This can be very awkwardly addressed too, though:

```

Reflect.defineProperty(StringSet.prototype, 'add', {
  configurable: true,
  value: {
    add(value) {
      return Reflect.getPrototypeOf(Reflect.getPrototypeOf(this)).add.call(this, test(value));
    }
  }.add
});
```

(To clarify I’m not obv not suggesting this is better than `class StringSet extends Set { ... }`, just want to understand what can’t presently be done other ways.)
valentinium at gmail.com (2018-07-24T02:37:01.816Z)
> That, and that the existing builtins already impose those limitations - and only class allows you to do those things, with them.

I’m surprised by that statement — it appeared to me that it currently
remains possible to create classes, including classes that extend
built-ins, with class syntax.

```
const test = value => {
  if (typeof value !== 'string') throw new TypeError('nope');
  return value;
};

function StringSet(init) {
  if (new.target === undefined)
    throw new TypeError('StringSet is not a constructor');
  if (init !== undefined)
    init = Array.from(init, test);

  return Reflect.construct(Set, [ init ], new.target);
}

Reflect.defineProperty(StringSet.prototype, 'add', {
  configurable: true,
  value: Object.setPrototypeOf({
    add(value) {
      return super.add(test(value));
    }
  }, Set.prototype).add
});

Reflect.defineProperty(StringSet.prototype, Symbol.toStringTag, {
  configurable: true,
  value: 'StringSet'
});

Reflect.setPrototypeOf(StringSet, Set);
Reflect.setPrototypeOf(StringSet.prototype, Set.prototype);

new StringSet('abc');
```

Not that this is something one is apt to want to do normally, though it
being possible does remain useful sometimes for meta/compositiony stuff. It
cannot be achieved in an <= ES5 environment, but it seems all the
reflection tools needed are present in environments that actually have
class syntax — even, despite the awkwardness necessitated by HomeObject
stuff, what is needed to employ super in methods.

I’m curious if, aside from the possibility of implementation-specific
things like type error messages being different, there there is anything
about the above class which ends up observably different from the ES-side
from one created with class syntax instead?

---

Edit: I can think of one. Because of how the home object’s prototype has been set for `add` here, reassigning the prototype of `StringSet.prototype` will not affect the super reference resolution as it would in a class-syntax class. This can be very awkwardly addressed too, though:

```

Reflect.defineProperty(StringSet.prototype, 'add', {
  configurable: true,
  value: {
    add(value) {
      return Reflect.getPrototypeOf(Reflect.getPrototypeOf(this)).add.call(this, test(value));
    }
  }.add
});
```
valentinium at gmail.com (2018-07-24T02:33:48.207Z)
> That, and that the existing builtins already impose those limitations - and only class allows you to do those things, with them.

I’m surprised by that statement — it appeared to me that it currently
remains possible to create classes, including classes that extend
built-ins, with class syntax.

```
const test = value => {
  if (typeof value !== 'string') throw new TypeError('nope');
  return value;
};

function StringSet(init) {
  if (new.target === undefined)
    throw new TypeError('StringSet is not a constructor');
  if (init !== undefined)
    init = Array.from(init, test);

  return Reflect.construct(Set, [ init ], new.target);
}

Reflect.defineProperty(StringSet.prototype, 'add', {
  configurable: true,
  value: Object.setPrototypeOf({
    add(value) {
      return super.add(test(value));
    }
  }, Set.prototype).add
});

Reflect.defineProperty(StringSet.prototype, Symbol.toStringTag, {
  configurable: true,
  value: 'StringSet'
});

Reflect.setPrototypeOf(StringSet, Set);
Reflect.setPrototypeOf(StringSet.prototype, Set.prototype);

new StringSet('abc');
```

Not that this is something one is apt to want to do normally, though it
being possible does remain useful sometimes for meta/compositiony stuff. It
cannot be achieved in an <= ES5 environment, but it seems all the
reflection tools needed are present in environments that actually have
class syntax — even, despite the awkwardness necessitated by HomeObject
stuff, what is needed to employ super in methods.

I’m curious if, aside from the possibility of implementation-specific
things like type error messages being different, there there is anything
about the above class which ends up observably different from the ES-side
from one created with class syntax instead?

---

Edit: I can think of one. Because of how the home object’s prototype has been set for `add` here, reassigning the prototype of `StringSet.prototype` will not affect the super reference resolution as it would in a class-syntax class.
valentinium at gmail.com (2018-07-24T02:25:09.701Z)
> That, and that the existing builtins already impose those limitations - and only class allows you to do those things, with them.

I’m surprised by that statement — it appeared to me that it currently
remains possible to create classes, including classes that extend
built-ins, with class syntax.

```
const test = value => {
  if (typeof value !== 'string') throw new TypeError('nope');
  return value;
};

function StringSet(init) {
  if (new.target === undefined)
    throw new TypeError('StringSet is not a constructor');
  if (init !== undefined)
    init = Array.from(init, test);

  return Reflect.construct(Set, [ init ], new.target);
}

Reflect.defineProperty(StringSet.prototype, 'add', {
  configurable: true,
  value: Object.setPrototypeOf({
    add(value) {
      return super.add(test(value));
    }
  }, Set.prototype).add
});

Reflect.defineProperty(StringSet.prototype, Symbol.toStringTag, {
  configurable: true,
  value: 'StringSet'
});

Reflect.setPrototypeOf(StringSet, Set);
Reflect.setPrototypeOf(StringSet.prototype, Set.prototype);

new StringSet('abc');
```

Not that this is something one is apt to want to do normally, though it
being possible does remain useful sometimes for meta/compositiony stuff. It
cannot be achieved in an <= ES5 environment, but it seems all the
reflection tools needed are present in environments that actually have
class syntax — even, despite the awkwardness necessitated by HomeObject
stuff, what is needed to employ super in methods.

I’m curious if, aside from the possibility of implementation-specific
things like type error messages being different, there there is anything
about the above class which ends up observably different from the ES-side
from one created with class syntax instead?