>On Mar 30, 2015, at 1:49 AM, Allen Wirfs-Brock <al...@wirfs-brock.com> wrote:

>There is no intrinsic reason why we needed to mandate that class constructors 
>should throw when called.  We even provided a simple and straight forward way
>(new.target===undefined) that a ES constructor body can use to determine 
>whether it was called or new’ed.  

I don’t think it’s great to have branches in a constructor dealing with this — 
it’s not super-obvious reading the code what it means (so it’s another thing to 
train people to understand).

A better way (which I think has been suggested by someone already in a 
different thread), would be to have a separate “magic” method to provide `call` 
code.

```js
class Buffer {
  constructor(…a) {
    // …
  }

  factory(…a) { // [@@factory](), __factory__(), whatever
    return new Buffer(…a);
    // Or whatever else one might wish to do in a factory method
  }
}
```

But, I think the factory problem is solved well enough with static methods

```js
class Buffer {
  constructor(…a) {
    this.initialize(…a);
  }

  // Much easier to understand these, compared with Buffer(someBuffer) or 
Buffer(someArray) etc
  static withBuffer(buffer) { assert(Buffer.isBuffer(buffer)); return new 
Buffer(buffer); }
  static withArray(array) { assert(Array.isArray(array)); return new  
Buffer(array); }
  static withSize(size) { assert(IsUInt(size)); return new Buffer(size); }
  static fromString(str, encoding = “utf8") { assert(IsString(str) && 
IsString(encoding)); return new Buffer(str, encoding); }

  initialize(…a) {
    switch (a.length) {
      case 1:
        if (IsUInt(a[0])) return allocateBufferOfSize(this, a[0]);
        else if (Array.isArray(a[0]) return allocateBufferFromArray(this, a[0]);
        else if (Buffer.isBuffer(a[0]) return allocateCopyOfBuffer(this, a[0]);
        else if (IsString(a[0]) { /* fall through */ }
        else ThrowTypeError(“Function called with incorrect arguments!");
      case 2:
        if (IsUndefined(a[1]) a[1] = “utf8”;
        if (IsString(a[0] && IsString(a[1]))  return 
allocateBufferFromString(this, a[0], a[1]);
      default:
        ThrowTypeError(“Function called with incorrect arguments!");
    }
  }
}
```

>I think we should just drop that throws when called feature of class 
>constructors..
>
>(The restriction was added to future proof for the possibility of inventing 
>some other way to provide a class with distinct new/call behavior. I don’t 
>think we need nor can afford to
>wait for the invention of a new mechanism which will inevitably be more 
>complex than new.target, which we already have.)

I’m all for it if it can be allowed without making classes more complicated for 
consumers to use — The thing I like about requiring `new` is that it’s very 
simple and straight forward.

But in either case, these (IsCallable / IsConstructor) are pretty basic 
qualities of objects that a Reflection* api ought to be able to read into, imho.

> 
> 
>> On Mar 29, 2015, at 11:51 PM, Caitlin Potter <caitpotte...@gmail.com> wrote:
>> 
>> ...
>> 
>> Reflect.isConstructor(fn) -> true if Class constructor, generator, or legacy 
>> (and non-builtin) function syntactic form
>> Reflect.isCallable(fn) -> true for pretty much any function, except for 
>> class constructors and a few builtins
> 
> I’ve already seen another situation (node’s Buffer) where code could be 
> simplified by using a ES6 class definition but where that is prevented 
> because a class constructor throws when called.
> 
> Just to clarify something.  Class constructors actually are “callable”.  You 
> can observe this by the fact that Proxy allows you to install an “apply” 
> handler (the reification of the [[[Call]] internal method) on a class 
> constructor.   The the fact that an object can be [[Call]]’ed is already 
> reflected  by the typeof operator.  Class constructors throw when called 
> because at the last minute we choose to make their [[Call]] do an explicit 
> throw not because they aren’t callable.
> 
> There is no intrinsic reason why we needed to mandate that class constructors 
> should throw when called.  We even provided a simple and straight forward way 
> (new.target===undefined) that a ES constructor body can use to determine 
> whether it was called or new’ed.  
> 
> I think we should just drop that throws when called feature of class 
> constructors..
> 
> (The restriction was added to future proof for the possibility of inventing 
> some other way to provide a class with distinct new/call behavior. I don’t 
> think we need nor can afford to wait for the invention of a new mechanism 
> which will inevitably be more complex than new.target, which we already have.)
> 
> Allen
> 
> 

_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to