Should I be able to apply `new`?
P T Withington wrote:
Suppose I have a function that wants to be able to construct
arbitrary objects and manipulate them:function maker () { var o = new arguments[0].apply(?, arguments.slice(1)); ... return o; }
The syntax does not allow for this. Should it?
I'd thought to do that you'd do something like this (don't have time to spec-verify at the moment, but this is in the right vein at least):
function maker () { var o = arguments[0].intrinsic::construct.apply(null, arguments.slice(1)); ... return o; }
The |null| is purely a guess; I suspect whatever's actually there is ignored.
On Apr 6, 2007, at 6:53 AM, Jeff Walden wrote:
function maker () { var o = arguments[0].intrinsic::construct.apply(null,
arguments.slice(1)); ... return o; }The |null| is purely a guess; I suspect whatever's actually there
is ignored.
Couple of updates:
- The hooks for get, set, etc. are in the meta namespace now.
- We eliminated meta::construct since classes have constructor syntax
already, and functions are a single special case. - There remain unaddressed use-cases for applyNew or whatever you'd
call it (Narcissus calls it applyConstructor).
I think we'll want something, but we haven't agreed on it yet. We
believe it should not be a hook below class constructor syntax that
allows specializing constructors. I would rather it were a helper
that has the right parameters (the arguments array for the new
application) and that's it. I'll propose this.
Brendan Eich wrote:
On Apr 6, 2007, at 6:53 AM, Jeff Walden wrote:
function maker () { var o = arguments[0].intrinsic::construct.apply(null,
arguments.slice(1)); ... return o; } The |null| is purely a guess; I suspect whatever's actually there
is ignored.Couple of updates:
- The hooks for get, set, etc. are in the meta namespace now.
- We eliminated meta::construct since classes have constructor syntax
already, and functions are a single special case.- There remain unaddressed use-cases for applyNew or whatever you'd
call it (Narcissus calls it applyConstructor).
Hold on, he didn't say meta::construct, he said intrinsic::construct.
Eliminating meta::construct is different from eliminating intrinsic::construct. The former was the proposed hook for a class to override the standard constructor protocol, in rare cases where you want to eg. memoize instances rather than allocate new ones.
We decided that's rare enough and confusing enough not to support meta::construct; it's easy enough to provide meta::invoke and tell your clients to call myClass(...) for such cases, rather than "new myClass(...)". We agreed that operator 'new' will always allocate and always run the standard construction protocol (inits, settings, ctors, in their base/derived nesting order). I don't have a strong opinion for or against this position, but it's what the committee concluded at the last meeting.
The latter -- intrinsic::construct -- is a function the runtime provides to let user code apply the standard construction protocol -- as in operator 'new' -- to a class and an arguments array. Just as Function.apply applies the standard calling protocol to a function and an arguments array. IMO we should be providing intrinsic::construct. It's in the reference impl at the moment.
On Apr 6, 2007, at 11:50 AM, Graydon Hoare wrote:
The latter -- intrinsic::construct -- is a function the runtime
provides to let user code apply the standard construction protocol -- as in operator 'new' -- to a class and an arguments array. Just as Function.apply applies the standard calling protocol to a function and an arguments array. IMO we should be providing intrinsic::construct. It's in the reference impl at the moment.
Oh, great -- I missed it in the meta separation.
What parameters does it take? (/me looks...) Ok, I see
magic::construct, but no intrinsic::construct. Little help?
Anyway, it's good to have a way to compose new and apply, IMHO. If
the parameterization is right, we are done. The right
parameterization includes the class or function and the arguments
array. It should not be a class-only thing.
On 2007-04-06, at 14:50 EDT, Graydon Hoare wrote:
Brendan Eich wrote:
On Apr 6, 2007, at 6:53 AM, Jeff Walden wrote:
function maker () { var o = arguments[0].intrinsic::construct.apply(null, arguments.slice(1)); ... return o; } The |null| is purely a guess; I suspect whatever's actually there is ignored.
Couple of updates:
- The hooks for get, set, etc. are in the meta namespace now.
- We eliminated meta::construct since classes have constructor syntax already, and functions are a single special case.
- There remain unaddressed use-cases for applyNew or whatever you'd call it (Narcissus calls it applyConstructor).
Hold on, he didn't say meta::construct, he said intrinsic::construct.
Eliminating meta::construct is different from eliminating intrinsic::construct. The former was the proposed hook for a class to override the standard constructor protocol, in rare cases where you
want to eg. memoize instances rather than allocate new ones.We decided that's rare enough and confusing enough not to support meta::construct; it's easy enough to provide meta::invoke and tell
your clients to call myClass(...) for such cases, rather than "new myClass(...)". We agreed that operator 'new' will always allocate and always run the standard construction protocol (inits, settings, ctors, in their base/derived nesting order). I don't have a strong opinion
for or against this position, but it's what the committee concluded at the last meeting.
I thought I could memoize by simply returning a value from my
constructor. Is that no longer true?
The latter -- intrinsic::construct -- is a function the runtime
provides to let user code apply the standard construction protocol -- as in operator 'new' -- to a class and an arguments array. Just as Function.apply applies the standard calling protocol to a function and an arguments array. IMO we should be providing intrinsic::construct. It's in the reference impl at the moment.
That answers my question that started this thread.
On Apr 6, 2007, at 12:49 PM, P T Withington wrote:
I thought I could memoize by simply returning a value from my constructor. Is that no longer true?
You're thinking of functions, not classes. Class constructors cannot
return e; -- they can only return; or fall off the end.
P T Withington wrote:
I thought I could memoize by simply returning a value from my constructor. Is that no longer true?
Ah, yes. A subtlety in the word "constructor": you can return any novel value you like from a constructor function, as this is legal ES3. But in ES4 we also have classes with constructors, and you cannot return novel values from a class constructor.
Class constructors are called as part of a specific sequence of nested base/derived actions, including instance initializers declared outside the ctor and instance settings declared between the parameter list and the ctor body. That sequence of actions assumes a certain continuity in the constructee: switching the value you're part-way through constructing in the middle of the sequence makes it very hard to formulate safety conditions that would preserve type judgments the verifier might wish to make, so we've prohibited it.
(In general any valid ES3 code, save a very few ill-specified or horrendously dangerous and unused cases, should be valid ES4 code. We know we can't break the web :)
Suppose I have a function that wants to be able to construct
arbitrary objects and manipulate them:
function maker () { var o = new arguments[0].apply(?, arguments.slice(1)); ... return o; }
The syntax does not allow for this. Should it?
Or should I have to use some more complicated way to apply a
constructor to arguments? Can I apply a class to call its constructor?
function maker () { var o = new arguments[0]; arguments[0].apply(o, arguments.slice(1)); ... return o; }