Minor issues with proxies

# Andreas Rossberg (14 years ago)

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/

# Tom Van Cutsem (14 years ago)
  • 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!

# Tom Van Cutsem (14 years ago)

Proxy.create{Function} is now present on < harmony:proxies_semantics>. Let us

know if you spot any further holes.

Cheers, Tom

2011/10/7 Tom Van Cutsem <tomvc.be at gmail.com>

# Andreas Rossberg (14 years ago)

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:

  1. 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).

# Andreas Rossberg (14 years ago)

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:

  1. 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).

# Tom Van Cutsem (14 years ago)

2011/10/12 Andreas Rossberg <rossberg at google.com>

One comment only:

  1. 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

# Andreas Rossberg (14 years ago)

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.)
# Tom Van Cutsem (14 years ago)

Fixed. I also updated the JS default traps to include better normalization of trap results.

2011/10/13 Andreas Rossberg <rossberg at google.com>