Minor issues with proxies
- Proxy.create: What if the handler passed is not an object? Should we
throw right away?
We think the most sensible thing to do is to call ToObject(handler), which will throw right away if the handler is not an object.
- Proxy.create: What if the prototype passed is neither an object nor null? FF silently sets it to null in all other cases, but that seems inconsistent with Object.create, which throws.
By analogy to Object.create, we should check: "If Type(O) is not Object or Null throw a TypeError exception." (where O would be the prototype)
- Proxy.createFunction: More of a question, but do we really want to support a separate construct trap for function proxies? I would argue that it was a mistake to ever make a distinction between a regular and a construct call. Even if we cannot clean that up, we should perhaps avoid having it proliferate further, in the proxy interface.
We need the construct trap to reliably emulate some of the built-in constructors that have distinct behaviors for [[Call]] and [[Construct]].
Your above questions made us realize that Proxy.create{Function} is currently not specified on the proxies:semantics page. Will fix shortly.
- Derived get/set traps: They use .call on accessor functions taken from a user-defined descriptor. Such a function might itself be a proxy, in which case .call is not necessarily defined. Should invoke it through Function.prototype.call.call instead. (There may be other places in the current ES spec that assume that all functions have a call method. I think they should all be changed.)
Could it be you are looking at the non-normative description of the derived get/set traps in Javascript itself, on the harmony:proxies page? The normative spec on the proxies:semantics page uses the "built-in" [[Call]] behavior.
- Also, we should specify that the JS code assumes that all used
intrinisc properties are the original methods.
There's already such a disclaimer at the top of that section (we just added a minor clarification): the JS code is non-normative. The normative specification assumes the original methods.
- Object.{seal,freeze,preventExtensions}: When sealing a function
proxy, how do we initialize the standard properties length, constructor, prototype, caller, and arguments? What if the proxy does not define them already, or returns unsuitable values?
"caller" and "arguments" should be poisoned, given that ES6 builds on ES5/strict.
For "length" or "prototype", since these are non-configurable, that will depend on our discussion on the FixedHandler and how to deal with non-configurable properties. Regardless of that discussion, we do think that these properties, if not specified by the pdmap returned by fix(), should at least default to the corresponding properties for the function proxy's callTrap.
"constructor" is not a property of functions, right?
- Function.prototype.toString: should this work for function proxies?
Yes, as specified as the last bullet of < harmony:proxies#semantics>:
Function.prototype.toString.call(aFunctionProxy) → returns the result of Function.prototype.toString.call(callTrap) where callTrap is the function proxy’s callTrap.
We should add this to the proxies:semantics page as well.
- Function.prototype.bind: requires additional language explaining how
the length property is set if the curried function is a proxy.
I think we previously agreed that the wording of Function.prototype.bind should change so that it explicitly calls [[Get]] to query the Target function for its "length" property and coerces the result to a non-negative integer.
- JSON: don't we need some changes here, too? For example, step 6a of the JO operation (15.12.3) talks about the "names of all the own properties" of an object. Clearly, for a proxy we need to invoke the appropriate trap here.
Like the above issue, it seems that this is not really an issue with proxies per se. Rather, the spec should be reformulated in terms of the appropriate internal methods. This is needed anyway to explain how JSON interacts with host objects.
- Outside the (current?) standard, but pragmatically, how should we treat .proto on a proxy? FF and V8 both treat it as an ordinary property for proxies, but that implies that Object.getPrototypeOf(p) != p.proto in general.
As part of the body of the normative spec, "proto" should simply be treated as a normal property name, just as it is on all other objects.
If appendix B would standardize the current de-facto behavior then it should also contain a section extending proxies to trap that behavior.
- ToStringArray, step 6.a: s/array/O/
Thanks for all these detailed remarks, much appreciated!
Proxy.create{Function} is now present on < harmony:proxies_semantics>. Let us
know if you spot any further holes.
Cheers, Tom
On 11 October 2011 20:49, Tom Van Cutsem <tomvc.be at gmail.com> wrote:
Proxy.create{Function} is now present on harmony:proxies_semantics. Let us know if you spot any further holes.
Great, thanks!
One comment only:
- Let handler be ToObject(O)
I wonder, is that useful at all? I don't see how ToObject can ever produce a useful handler from a non-object. It may be more helpful to throw a TypeError right away if the handler is not an object (like you do for non-object protos).
On 12 October 2011 11:00, Andreas Rossberg <rossberg at google.com> wrote:
On 11 October 2011 20:49, Tom Van Cutsem <tomvc.be at gmail.com> wrote:
Proxy.create{Function} is now present on harmony:proxies_semantics. Let us know if you spot any further holes.
Great, thanks!
One comment only:
- Let handler be ToObject(O)
I wonder, is that useful at all? I don't see how ToObject can ever produce a useful handler from a non-object. It may be more helpful to throw a TypeError right away if the handler is not an object (like you do for non-object protos).
I think it might also be useful to have the prototype argument default to null (i.e. convert undefined to null in/before step 2).
2011/10/12 Andreas Rossberg <rossberg at google.com>
One comment only:
- Let handler be ToObject(O)
I wonder, is that useful at all? I don't see how ToObject can ever produce a useful handler from a non-object. It may be more helpful to throw a TypeError right away if the handler is not an object (like you do for non-object protos).
You're right, a wrapped primitive isn't going to be much of a handler.
I think it might also be useful to have the prototype argument default
to null (i.e. convert undefined to null in/before step 2).
Absolutely, I forgot this. The intent is indeed for Proto to default to null.
Thanks, Tom
On more thing:
- Filter[Own]Enumerable: don't anticipate the case that desc might be undefined in step 7.c.4. (The respective JS default traps are broken in a similar manner.)
Fixed. I also updated the JS default traps to include better normalization of trap results.
2011/10/13 Andreas Rossberg <rossberg at google.com>
Tom!
I understand that you are currently working on finalizing a number of aspects of the proxies proposal, so I thought I'd send my current notes on issues I discovered. (Sorry if I'm a bit late with that, but I just returned from travelling.)
Here is a list of minor issues. I'll send a separate mail describing what I think is a more fundamental problem with the current spec.
Proxy.create: What if the handler passed is not an object? Should we throw right away?
Proxy.create: What if the prototype passed is neither an object nor null? FF silently sets it to null in all other cases, but that seems inconsistent with Object.create, which throws.
Proxy.createFunction: More of a question, but do we really want to support a separate construct trap for function proxies? I would argue that it was a mistake to ever make a distinction between a regular and a construct call. Even if we cannot clean that up, we should perhaps avoid having it proliferate further, in the proxy interface.
Derived get/set traps: They use .call on accessor functions taken from a user-defined descriptor. Such a function might itself be a proxy, in which case .call is not necessarily defined. Should invoke it through Function.prototype.call.call instead. (There may be other places in the current ES spec that assume that all functions have a call method. I think they should all be changed.)
Also, we should specify that the JS code assumes that all used intrinisc properties are the original methods.
Object.{seal,freeze,preventExtensions}: When sealing a function proxy, how do we initialize the standard properties length, constructor, prototype, caller, and arguments? What if the proxy does not define them already, or returns unsuitable values?
Function.prototype.toString: should this work for function proxies?
Function.prototype.bind: requires additional language explaining how the length property is set if the curried function is a proxy.
JSON: don't we need some changes here, too? For example, step 6a of the JO operation (15.12.3) talks about the "names of all the own properties" of an object. Clearly, for a proxy we need to invoke the appropriate trap here.
Outside the (current?) standard, but pragmatically, how should we treat .proto on a proxy? FF and V8 both treat it as an ordinary property for proxies, but that implies that Object.getPrototypeOf(p) != p.proto in general.
ToStringArray, step 6.a: s/array/O/