>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