>On Mar 30, 2015, at 1:49 AM, Allen Wirfs-Brock <[email protected]> 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 <[email protected]> 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
[email protected]
https://mail.mozilla.org/listinfo/es-discuss