Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-12-10 Thread Tom Van Cutsem
To pick up this thread again, I gave a talk about the trade-offs in
designing JS proxies at a meeting last week. The people following this
thread may be interested in seeing the slides: 
http://soft.vub.ac.be/~tvcutsem/invokedynamic/presentations/Tradeoffs_WGLD2012_Austin.pdf
(the talk tremendously simplifies the story to cram it in 25 minutes. I
added some minimal notes to make the slides easier to follow.

The talk is more or less a story about how we started out with non-direct
proxies and ended up with direct-proxies. It doesn't provide any new
insights or discuss the recent notification proxies or action-proxies.

Cheers,
Tom

2012/12/3 David Bruant bruan...@gmail.com

 Le 03/12/2012 16:38, Mark S. Miller a écrit :

  What eternal[1] invariant does this bypass?

 [1] https://mail.mozilla.org/**pipermail/es-discuss/2011-May/**
 014150.htmlhttps://mail.mozilla.org/pipermail/es-discuss/2011-May/014150.html

 Apparently none... Yet, additionally to the last case I showed, there is
 also:

 var p = new Proxy({a:1}, {
 isExtensible: function(target, action){
 var v = action();
 Object.preventExtensions(**target);
 }
 })

 // real life-like code?
 if(Object.isExtensible(target)**){
 Object.defineProperty(target, 'b', {value: 37}); // throws
 }

 I agree it's not an eternal invariant, but it's quite surprising.
 [cc'ing Tom to make sure he reads this part]
 Arguably, the isExtensible, seal and freeze trap could have no action
 and just forward to the target. That's what the current invariant
 enforcement suggests anyway (Invariant check: check whether the boolean
 trap result is equal to isFrozen(target), isSealed(target) or
 isExtensible(target)).
 This applies to current proxies actually. Maybe their return value could
 just be ignored. Trap authors have all the information they need with the
 trap arguments to decide whether they want to throw. For the rest, the
 operation can just be forwarded to the target (which it has to for
 invariant check already).


 Proxies-with-action have this weird taste of one-move ahead; like if
 they could run what they're expected and then play a bit more of the game
 before actually showing their before-last move. It makes sense they do not
 violate eternal invariants

 Although not rigorously necessary when it comes to the very minimalistic
 eternal invariants, the current proxies provides some guarantees by design
 which are nice both for whoever writes handlers and whoever manipulates
 proxies.

 Unrelated, but I think that custom property descriptor attributes are lost
 with action-proxies. I'm not sure yet what is a good way to recover them.

 David


  On Mon, Dec 3, 2012 at 3:33 AM, David Bruant bruan...@gmail.com wrote:

 Le 03/12/2012 00:06, David Bruant a écrit :

  The call to action performs
 the original operation on target and remembers the result. After the
 trap returns, the proxy returns the remembered result of action.

  target = {a:1};
  var p = new Proxy(target, {
  get: function(target, name, action){
  var v = action();
  target[name] = 2;
  }
  })

  p.a; // ?

 If p.a is 1 because the call to action remembered the 1, then the
 target and the proxy look awkwardly desynchronized. To know what's being
 returned from the trap, one needs to remember when the action is being
 called which makes writing traps harder I feel. With the current design,
 looking at the return statements is enough.
 If p.a is 2, I don't understand the point of action. Or at least, I
 don't see how it's better than just calling Reflect[trap].

 I've found much MUCH worse:


  target = {a:1};
  var p = new Proxy(target, {
  get: function(target, name, action){
  var v = action();
  Object.defineProperty(target, name, {value:2, configurable:
 false, writable:false})
  }
  })

  p.a; // 1 ?

 In that case, the mechanism used to bypass invariant checking is a way to
 bypass invariants entirely.


 David
 __**_
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/**listinfo/es-discusshttps://mail.mozilla.org/listinfo/es-discuss





___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-12-03 Thread David Bruant

Le 03/12/2012 00:06, David Bruant a écrit :

The call to action performs
the original operation on target and remembers the result. After the
trap returns, the proxy returns the remembered result of action.

target = {a:1};
var p = new Proxy(target, {
get: function(target, name, action){
var v = action();
target[name] = 2;
}
})

p.a; // ?

If p.a is 1 because the call to action remembered the 1, then the 
target and the proxy look awkwardly desynchronized. To know what's 
being returned from the trap, one needs to remember when the action is 
being called which makes writing traps harder I feel. With the current 
design, looking at the return statements is enough.
If p.a is 2, I don't understand the point of action. Or at least, I 
don't see how it's better than just calling Reflect[trap].

I've found much MUCH worse:

target = {a:1};
var p = new Proxy(target, {
get: function(target, name, action){
var v = action();
Object.defineProperty(target, name, {value:2, configurable: 
false, writable:false})

}
})

p.a; // 1 ?

In that case, the mechanism used to bypass invariant checking is a way 
to bypass invariants entirely.


David
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-12-03 Thread Mark S. Miller
What eternal[1] invariant does this bypass?

[1] https://mail.mozilla.org/pipermail/es-discuss/2011-May/014150.html

On Mon, Dec 3, 2012 at 3:33 AM, David Bruant bruan...@gmail.com wrote:
 Le 03/12/2012 00:06, David Bruant a écrit :

 The call to action performs
 the original operation on target and remembers the result. After the
 trap returns, the proxy returns the remembered result of action.

 target = {a:1};
 var p = new Proxy(target, {
 get: function(target, name, action){
 var v = action();
 target[name] = 2;
 }
 })

 p.a; // ?

 If p.a is 1 because the call to action remembered the 1, then the
 target and the proxy look awkwardly desynchronized. To know what's being
 returned from the trap, one needs to remember when the action is being
 called which makes writing traps harder I feel. With the current design,
 looking at the return statements is enough.
 If p.a is 2, I don't understand the point of action. Or at least, I
 don't see how it's better than just calling Reflect[trap].

 I've found much MUCH worse:


 target = {a:1};
 var p = new Proxy(target, {
 get: function(target, name, action){
 var v = action();
 Object.defineProperty(target, name, {value:2, configurable:
 false, writable:false})
 }
 })

 p.a; // 1 ?

 In that case, the mechanism used to bypass invariant checking is a way to
 bypass invariants entirely.


 David
 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss



-- 
Cheers,
--MarkM
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-12-03 Thread David Bruant

Le 03/12/2012 16:38, Mark S. Miller a écrit :

What eternal[1] invariant does this bypass?

[1] https://mail.mozilla.org/pipermail/es-discuss/2011-May/014150.html
Apparently none... Yet, additionally to the last case I showed, there is 
also:


var p = new Proxy({a:1}, {
isExtensible: function(target, action){
var v = action();
Object.preventExtensions(target);
}
})

// real life-like code?
if(Object.isExtensible(target)){
Object.defineProperty(target, 'b', {value: 37}); // throws
}

I agree it's not an eternal invariant, but it's quite surprising.
[cc'ing Tom to make sure he reads this part]
Arguably, the isExtensible, seal and freeze trap could have no action 
and just forward to the target. That's what the current invariant 
enforcement suggests anyway (Invariant check: check whether the boolean 
trap result is equal to isFrozen(target), isSealed(target) or 
isExtensible(target)).
This applies to current proxies actually. Maybe their return value could 
just be ignored. Trap authors have all the information they need with 
the trap arguments to decide whether they want to throw. For the rest, 
the operation can just be forwarded to the target (which it has to for 
invariant check already).



Proxies-with-action have this weird taste of one-move ahead; like if 
they could run what they're expected and then play a bit more of the 
game before actually showing their before-last move. It makes sense they 
do not violate eternal invariants


Although not rigorously necessary when it comes to the very minimalistic 
eternal invariants, the current proxies provides some guarantees by 
design which are nice both for whoever writes handlers and whoever 
manipulates proxies.


Unrelated, but I think that custom property descriptor attributes are 
lost with action-proxies. I'm not sure yet what is a good way to recover 
them.


David


On Mon, Dec 3, 2012 at 3:33 AM, David Bruant bruan...@gmail.com wrote:

Le 03/12/2012 00:06, David Bruant a écrit :


The call to action performs
the original operation on target and remembers the result. After the
trap returns, the proxy returns the remembered result of action.

 target = {a:1};
 var p = new Proxy(target, {
 get: function(target, name, action){
 var v = action();
 target[name] = 2;
 }
 })

 p.a; // ?

If p.a is 1 because the call to action remembered the 1, then the
target and the proxy look awkwardly desynchronized. To know what's being
returned from the trap, one needs to remember when the action is being
called which makes writing traps harder I feel. With the current design,
looking at the return statements is enough.
If p.a is 2, I don't understand the point of action. Or at least, I
don't see how it's better than just calling Reflect[trap].

I've found much MUCH worse:


 target = {a:1};
 var p = new Proxy(target, {
 get: function(target, name, action){
 var v = action();
 Object.defineProperty(target, name, {value:2, configurable:
false, writable:false})
 }
 })

 p.a; // 1 ?

In that case, the mechanism used to bypass invariant checking is a way to
bypass invariants entirely.


David
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss





___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-12-02 Thread Tom Van Cutsem
2012/11/28 Brandon Benvie bran...@brandonbenvie.com

 Object.observe would fit under after correct?


Yes, with two remarks:
- it only traps updating operations
- the traps are called in a separate turn (i.e. asynchronously), so they
cannot change the result of the operation

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-12-02 Thread Tom Van Cutsem
2012/11/28 David Bruant bruan...@gmail.com

  I don't understand why a unique token per trap invocation would be
 necessary.

 I still don't understand this point.
 I've gone spelunking. I've found:
 * the wiki page [1] (reflecting July meeting) which mentions that
 returning undefined would express I don't know the private name, please
 forward
 * Confirmed on July 31st [2].
 * Introduction of the idea of putting the verification of known names
 somewhere else than for each trap return [3]. Some discussion in between
 about this idea. Introduction of the idea of adding a third argument [4]
 after which I think stops all discussions about returning something in
 traps to prove knowledge of a private name or forwarding when not knowing.

 I don't remember the point about a token per trap invocation and I haven't
 been able to find it (but I haven't read everything).

 In any case, for throw ForwardToTarget, I don't see why it would be
 necessary. It seems it would work unambiguously with meta-handlers, with
 target-as-a-proxy or with manipulate-any-other-proxy-inside-a-trap (which
 target-as-a-proxy is an instance of).


I think throwing a special token, as is done with StopIteration would
probably work in practice (little risk of confusing it with a legitimately
returned value). However, it does require every trap invocation to be
wrapped in a try-catch block to potentially catch that error. Maybe I'm too
influenced by the JVM, but my understanding is that wrapping every call to
a trap with a try-catch block won't be free. Perhaps implementors can
comment.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-12-02 Thread Tom Van Cutsem
2012/11/29 Dean Tribble dtrib...@gmail.com

 As a general point, I encourage you to look for other inspiration than
 CLOS MOP for doign proxies (whose mother was really InterlispD). Meta-level
 access deeply impacts security,maintainability,
 reliability, understandability, etc. The tighter and more structured you
 can make your meta-level access, the easier it will be to to implement,
 use, and maintain (e.g., both coroutines and downward functions are more
 understandable, easier to implement, easier to secure, etc. than general
 continuations and call-cc).


I agree (side note: the CLOS MOP didn't form a direct inspiration for JS
proxies, although I'm probably influenced by having studied it).




 CLOS method combinations allow a composer to distinguish between
 before, after and around-style composition:
 - before-style wrapping gives you only the ability to get notified
 before an operation happens. You can abort, but not change, the result of
 the operation. This is what notification-proxies offer.


 You *can* change the result of the operation. You do so by modifying the
 state before the operation proceeds, of course. You could also extend the
 notification support to notify after so you could clenup (avoiding a
 callback hack).


Indeed. I think notification proxies would benefit from both before + after
notification so any cleanup of virtual properties can be done directly.

That just leaves the thorny issue that for virtual object abstractions,
having to set-up the target in a before-handler and clean-up the target
in an after-handler is really a very indirect way of expressing the
abstraction, especially if the proxy doesn't need to virtualize any
invariants.




 - after-style wrapping allows you to get notified of an operation
 after-the-fact. Depending on the API, the after-wrapper may or may not
 get to see the outcome of the operation, and may or may not change the
 final outcome passed on to clients.
 - around-style wrapping is the most general and allows the composer to
 decide if and when to forward, and what result to return. It subsumes
 before/after wrapping. This is what direct proxies currently provide.


 It does not subsume before/after wrapping, because it loses the integrity
 of before/after (e.g., the wrapper can lie and cheat, where the before and
 after cannot).  That may be worth it, but it is substantially different.


You're right, around doesn't subsume before+after in that regard. Thanks
for clarifying.



 Another variant is the differential version:  the differential trap is
 like a notification, but it can also return virtual additions (or an
 iterator of additions).  The proxy then invokes the primitive on the
 target, and appends (with de-dupping, etc.) the virtual additions. This
 allows the simple case to just use hte target, but also allows all of
 Allen's additional cases.



 As far as I can tell, virtual object abstractions like remote/persistent
 objects require around-style wrapping, because there's otherwise no
 meaningful target to automatically forward to.


 I thought the target in that case is an internal object to represent or
 reify the meta-state of the remote or persistent object. I think that still
 makes sense in both the persistent object and remote object cases.


It does. It just feels awkward, after having been able to express these
abstractions more directly with the current Proxy API for so long.




 Here's a list of use cases that I frequently have in mind when thinking
 about proxies, categorized according to whether the use case requires
 before/after/around wrapping:

 Virtual objects, hence around-style:
 - self-hosting exotic objects such as Date, Array (i.e. self-host an
 ES5/ES6 environment)
 - self-hosting DOM/WebIDL objects such as NodeList


 I should note that I'm not advocating a notification-only style for all
 your proxy needs; having get operations able to generate virtual results
 makes lots of sense. I primary suggest it for operations that are currently
 implemented by the system (i.e., user code cannot normally intervene) and
 that might be relied on for security-relevant behavior. wrapping return
 results of user operations in a proxy makes perfect sense to me.


It's hard to force the two different use cases (wrapping vs virtual
objects) into a single API. I don't have a good answer yet on how to
resolve the trade-offs.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-12-02 Thread David Bruant

Le 02/12/2012 17:27, Tom Van Cutsem a écrit :

2012/11/28 David Bruant bruan...@gmail.com mailto:bruan...@gmail.com


I don't understand why a unique token per trap invocation would
be necessary.

I still don't understand this point.
I've gone spelunking. I've found:
* the wiki page [1] (reflecting July meeting) which mentions that
returning undefined would express I don't know the private name,
please forward
* Confirmed on July 31st [2].
* Introduction of the idea of putting the verification of known
names somewhere else than for each trap return [3]. Some
discussion in between about this idea. Introduction of the idea of
adding a third argument [4] after which I think stops all
discussions about returning something in traps to prove knowledge
of a private name or forwarding when not knowing.

I don't remember the point about a token per trap invocation and I
haven't been able to find it (but I haven't read everything).

In any case, for throw ForwardToTarget, I don't see why it would
be necessary. It seems it would work unambiguously with
meta-handlers, with target-as-a-proxy or with
manipulate-any-other-proxy-inside-a-trap (which target-as-a-proxy
is an instance of).


I think throwing a special token, as is done with StopIteration would 
probably work in practice (little risk of confusing it with a 
legitimately returned value). However, it does require every trap 
invocation to be wrapped in a try-catch block to potentially catch 
that error.
Yes and no. The try-catch is inside the engine, very much like for 
StorIteration in for-of loops.
In case current implementations had performance drawbacks, I feel they 
could special-case when they know they are calling a function in the 
context of a particular protocol (iterator or proxy trap for instance).


Maybe I'm too influenced by the JVM, but my understanding is that 
wrapping every call to a trap with a try-catch block won't be free.
The more interesting question is whether it would be significantly 
cheaper than 'returning a value+invariant checks' because that's the 
reason I suggested the addition of throw ForwardToTarget.



Perhaps implementors can comment.

Yep.

David
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-12-02 Thread David Bruant

Le 02/12/2012 17:43, David Bruant a écrit :
Maybe I'm too influenced by the JVM, but my understanding is that 
wrapping every call to a trap with a try-catch block won't be free.
The more interesting question is whether it would be significantly 
cheaper than 'returning a value+invariant checks' because that's the 
reason I suggested the addition of throw ForwardToTarget.

Filed https://bugzilla.mozilla.org/show_bug.cgi?id=817401

David
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-12-02 Thread Mark S. Miller
On Sun, Dec 2, 2012 at 8:40 AM, Tom Van Cutsem tomvc...@gmail.com wrote:
 - after-style wrapping allows you to get notified of an operation
 after-the-fact. Depending on the API, the after-wrapper may or may not get
 to see the outcome of the operation, and may or may not change the final
 outcome passed on to clients.
 - around-style wrapping is the most general and allows the composer to
 decide if and when to forward, and what result to return. It subsumes
 before/after wrapping. This is what direct proxies currently provide.


 It does not subsume before/after wrapping, because it loses the integrity
 of before/after (e.g., the wrapper can lie and cheat, where the before and
 after cannot).  That may be worth it, but it is substantially different.


 You're right, around doesn't subsume before+after in that regard. Thanks for
 clarifying.

I think we can rescue around wrapping. I'll call this approach opaque
around wrapping. The idea is that the proxy passes into the handler
trap a proxy-generated no-argument function (a thunk) called action.
The normal case is that the trap does stuff before calling action,
calls action with no arguments and ignoring action's results, does
stuff after action, and returns nothing. The call to action performs
the original operation on target and remembers the result. After the
trap returns, the proxy returns the remembered result of action.

Open questions that take us to different design possibilities:
1) what happens if the trap does not call action?
2) what happens if the trap calls action more than once?
3) do actions ever return anything, in case the trap wants to pay
attention to it?
4) are there any return values from the trap that the proxy would pay
attention to?
5) if the original operation performed by action throws, should the
action still just return to the trap normally?
6) what happens if the trap throws rather that returning?

Two attractive possibilities:

A) A simple pure notification approach:
1) the proxy throws, indicating that the action was not performed
2) only the last successful action counts
3) a boolean, indicating whether the original operation succeeded on target
4) no
5) yes, but with false rather than true, as in #A.3 above.
6) the proxy throws, even though the action was performed.

B) Notification with fallback to virtual properties with invariant checking:
Like #A, except
1) if action is never called, then the trap return's invariants are
checked, as now.
4) only if action was never called.

I prefer #A to #B as it gains the full benefits of simplifying the
overall spec and implementation. However, #B still seems better than
current direct proxies, as the normal case gets target-maintenance and
invariant checking for free.


--
Cheers,
--MarkM
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-12-02 Thread Tom Van Cutsem
2012/12/2 Mark S. Miller erig...@google.com

 I think we can rescue around wrapping. I'll call this approach opaque
 around wrapping. The idea is that the proxy passes into the handler
 trap a proxy-generated no-argument function (a thunk) called action.


Interesting. I had thought of a similar approach, but hadn't pursued it
because I thought allocating a thunk per trap invocation would be deemed
too expensive. I'll go ahead and sketch the design, which I think
corresponds closely with your approach B)

First, from the point-of-view of the trap implementor, things would work as
follows (I show the defineProperty trap only as an example)

All traps take an extra thunk as last argument, which I will name
forward, since calling that thunk has the effect of forwarding the
operation to the target, returning the original result.

defineProperty: function(target, name, desc, forward) {
  // before
  var result = forward();
  // after
  return result;
}

Now, from the point-of-view of the proxy implementation, how is the above
trap called?

// in the proxy, intercepting Object.defineProperty(proxy, name, desc)
// where proxy = Proxy(target, handler)
var result = Uninitialized;
var thunk = function() {
  if (result === Disabled) throw new Error(can only call forward() during
trap invocation);
  if (result !== Uninitialized) throw new Error(forward() can be called
only once);
  result = Reflect.defineProperty(target, name, desc); // forward to target
  return result;
};
var trapResult = handler[defineProperty].call(handler, target, name,
desc, thunk);
if (result !== Uninitialized  result === trapResult) return result; // no
invariant checks when original result is returned
if (result === Uninitialized || result !== trapResult) { /* do invariant
checks */ ; return result; }
result = Disabled; // ensures one cannot call forward() outside of dynamic
extent of the invocation

I'll answer your questions for the above design:


 Open questions that take us to different design possibilities:
 1) what happens if the trap does not call action?

Invariant checks are performed on the returned result.


 2) what happens if the trap calls action more than once?

An exception is thrown.


 3) do actions ever return anything, in case the trap wants to pay
 attention to it?

Yes, it returns the value of the operation, applied to the target.


 4) are there any return values from the trap that the proxy would pay
 attention to?

Yes. If the trap returns the original result, it doesn't do any extra
checks. Otherwise it does.


 5) if the original operation performed by action throws, should the
 action still just return to the trap normally?

A thrown exception would escape and abort the entire operation, unless the
trap wraps the call to forward() in a try-catch block.


 6) what happens if the trap throws rather that returning?

Thrown exceptions are always propagated to clients.


 I prefer #A to #B as it gains the full benefits of simplifying the
 overall spec and implementation. However, #B still seems better than
 current direct proxies, as the normal case gets target-maintenance and
 invariant checking for free.


I agree that #B doesn't really simplify anything in the spec (the invariant
checks are still there sometimes).
I'm not sure if it is inherently better than the current design though: we
gain performance in terms of avoiding invariant checks, but we lose
performance by having to allocate a per-call thunk, + the API becomes more
complex (an additional parameter to every trap)

I do think that passing an action or forward() thunk to a trap as extra
argument beats David's proposed throw ForwardToTarget trick in terms of
elegance and usability (maybe not in terms of performance).

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-12-02 Thread Allen Wirfs-Brock

On Dec 2, 2012, at 11:40 AM, Tom Van Cutsem wrote:

 2012/12/2 Mark S. Miller erig...@google.com
 I think we can rescue around wrapping. I'll call this approach opaque
 around wrapping. The idea is that the proxy passes into the handler
 trap a proxy-generated no-argument function (a thunk) called action.
 
 Interesting. I had thought of a similar approach, but hadn't pursued it 
 because I thought allocating a thunk per trap invocation would be deemed too 
 expensive. I'll go ahead and sketch the design, which I think corresponds 
 closely with your approach B)

This is my first reaction too.  I want Proxies to be lightweight enough so they 
really can be used be used for things like self hosting built-ins and web API 
objects.  The need to create an pass in a action thunk on each trap calls 
initially feels too expensive.

But that is only a first reaction.  Perhaps the expense really isn't that 
great. Or perhaps a lot of the cases where I have assumed the Proxies would be 
needed could be handled by lightweight mechanisms such such as the 
@elementGet/@elementSet hooks described in 
http://wiki.ecmascript.org/doku.php?id=strawman:object_model_reformation  (see 
Implementing Built-inArray without Proxy and Rationalizing DOM HTMLCollections 
examples)

Allen











 
 First, from the point-of-view of the trap implementor, things would work as 
 follows (I show the defineProperty trap only as an example)
 
 All traps take an extra thunk as last argument, which I will name forward, 
 since calling that thunk has the effect of forwarding the operation to the 
 target, returning the original result.
 
 defineProperty: function(target, name, desc, forward) {
   // before
   var result = forward();
   // after
   return result;
 }
 
 Now, from the point-of-view of the proxy implementation, how is the above 
 trap called?
 
 // in the proxy, intercepting Object.defineProperty(proxy, name, desc)
 // where proxy = Proxy(target, handler)
 var result = Uninitialized;
 var thunk = function() {
   if (result === Disabled) throw new Error(can only call forward() during 
 trap invocation);
   if (result !== Uninitialized) throw new Error(forward() can be called only 
 once);
   result = Reflect.defineProperty(target, name, desc); // forward to target
   return result;
 };
 var trapResult = handler[defineProperty].call(handler, target, name, desc, 
 thunk);
 if (result !== Uninitialized  result === trapResult) return result; // no 
 invariant checks when original result is returned
 if (result === Uninitialized || result !== trapResult) { /* do invariant 
 checks */ ; return result; }
 result = Disabled; // ensures one cannot call forward() outside of dynamic 
 extent of the invocation
 
 I'll answer your questions for the above design:
  
 Open questions that take us to different design possibilities:
 1) what happens if the trap does not call action?
 Invariant checks are performed on the returned result.
  
 2) what happens if the trap calls action more than once?
 An exception is thrown.
  
 3) do actions ever return anything, in case the trap wants to pay
 attention to it?
 Yes, it returns the value of the operation, applied to the target.
  
 4) are there any return values from the trap that the proxy would pay
 attention to?
 Yes. If the trap returns the original result, it doesn't do any extra checks. 
 Otherwise it does.
  
 5) if the original operation performed by action throws, should the
 action still just return to the trap normally?
 A thrown exception would escape and abort the entire operation, unless the 
 trap wraps the call to forward() in a try-catch block.
  
 6) what happens if the trap throws rather that returning?
 Thrown exceptions are always propagated to clients.
  
 I prefer #A to #B as it gains the full benefits of simplifying the
 overall spec and implementation. However, #B still seems better than
 current direct proxies, as the normal case gets target-maintenance and
 invariant checking for free.
 
 I agree that #B doesn't really simplify anything in the spec (the invariant 
 checks are still there sometimes).
 I'm not sure if it is inherently better than the current design though: we 
 gain performance in terms of avoiding invariant checks, but we lose 
 performance by having to allocate a per-call thunk, + the API becomes more 
 complex (an additional parameter to every trap)
 
 I do think that passing an action or forward() thunk to a trap as extra 
 argument beats David's proposed throw ForwardToTarget trick in terms of 
 elegance and usability (maybe not in terms of performance).
 
 Cheers,
 Tom
 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-12-02 Thread David Bruant

Le 02/12/2012 18:34, Mark S. Miller a écrit :

On Sun, Dec 2, 2012 at 8:40 AM, Tom Van Cutsem tomvc...@gmail.com wrote:

- after-style wrapping allows you to get notified of an operation
after-the-fact. Depending on the API, the after-wrapper may or may not get
to see the outcome of the operation, and may or may not change the final
outcome passed on to clients.
- around-style wrapping is the most general and allows the composer to
decide if and when to forward, and what result to return. It subsumes
before/after wrapping. This is what direct proxies currently provide.


It does not subsume before/after wrapping, because it loses the integrity
of before/after (e.g., the wrapper can lie and cheat, where the before and
after cannot).  That may be worth it, but it is substantially different.


You're right, around doesn't subsume before+after in that regard. Thanks for
clarifying.

I think we can rescue around wrapping. I'll call this approach opaque
around wrapping. The idea is that the proxy passes into the handler
trap a proxy-generated no-argument function (a thunk) called action.
The normal case is that the trap does stuff before calling action,
calls action with no arguments and ignoring action's results, does
stuff after action, and returns nothing.
The point of around is to do something with the result in the middle 
of the trap, isn't it? For question 3, I'd answer that the action 
should return the result.



The call to action performs
the original operation on target and remembers the result. After the
trap returns, the proxy returns the remembered result of action.

target = {a:1};
var p = new Proxy(target, {
get: function(target, name, action){
var v = action();
target[name] = 2;
}
})

p.a; // ?

If p.a is 1 because the call to action remembered the 1, then the 
target and the proxy look awkwardly desynchronized. To know what's being 
returned from the trap, one needs to remember when the action is being 
called which makes writing traps harder I feel. With the current design, 
looking at the return statements is enough.
If p.a is 2, I don't understand the point of action. Or at least, I 
don't see how it's better than just calling Reflect[trap].



1) what happens if the trap does not call action?
If calling action was made compulsory, then, it would have the same 
downsides than the notification proxies when it comes like virtual 
objects including the necessity of a physical backing.


David
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-12-02 Thread David Bruant

Le 02/12/2012 20:40, Tom Van Cutsem a écrit :

2012/12/2 Mark S. Miller erig...@google.com mailto:erig...@google.com

I think we can rescue around wrapping. I'll call this approach opaque
around wrapping. The idea is that the proxy passes into the handler
trap a proxy-generated no-argument function (a thunk) called action.


Interesting. I had thought of a similar approach, but hadn't pursued 
it because I thought allocating a thunk per trap invocation would be 
deemed too expensive. I'll go ahead and sketch the design, which I 
think corresponds closely with your approach B)
I think that for most traps, action could be a deeply frozen wrapped 
version of Reflect.trap. It would reduce action functions to one per 
trap which would be much better than one per trap invocation.



4) are there any return values from the trap that the proxy would pay
attention to?

Yes. If the trap returns the original result, it doesn't do any extra 
checks. Otherwise it does.
Said a bit differently, the extra check is reduced to the equality 
between the return value of action and trap return value.



I prefer #A to #B as it gains the full benefits of simplifying the
overall spec and implementation. However, #B still seems better than
current direct proxies, as the normal case gets target-maintenance and
invariant checking for free.


I agree that #B doesn't really simplify anything in the spec (the 
invariant checks are still there sometimes).
I'm not sure if it is inherently better than the current design 
though: we gain performance in terms of avoiding invariant checks, but 
we lose performance by having to allocate a per-call thunk, + the API 
becomes more complex (an additional parameter to every trap)


I do think that passing an action or forward() thunk to a trap as 
extra argument beats David's proposed throw ForwardToTarget trick in 
terms of elegance and usability (maybe not in terms of performance).
I agree it looks less hacky. But I'm not entirely convinced when it 
comes to usability. As mentioned in the other answer, it makes 
understanding the trap a bit harder because what comes out of the trap 
may be less clear: since there is no explicit return statement, one has 
to figure out, what the value of the action function specifically when 
it's called for the around case.


David
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-11-28 Thread Tom Van Cutsem
2012/11/26 Dean Tribble dtrib...@gmail.com

 On Mon, Nov 26, 2012 at 11:33 AM, Tom Van Cutsem tomvc...@gmail.comwrote:

 Thanks for spelling out these examples. While they still don't feel like
 actual important use cases to support, they give a good flavor of the kinds
 of compromises we'd need to make when turning to notification-only proxies.


 I agree. My usual expectation for proxies is to support remote and
 persistent objects. While supporting other scenarios is great, usually
 that's incidental.  Is there a broader list of aspirations for proxies? or
 is this just a all else being equal it would be good if we can do this?


Let's talk about aspirations for proxies. It will help us set priorities.

First, some terminology (originating from CLOS, the mother of all MOPs ;-)
CLOS method combinations allow a composer to distinguish between before,
after and around-style composition:
- before-style wrapping gives you only the ability to get notified before
an operation happens. You can abort, but not change, the result of the
operation. This is what notification-proxies offer.
- after-style wrapping allows you to get notified of an operation
after-the-fact. Depending on the API, the after-wrapper may or may not
get to see the outcome of the operation, and may or may not change the
final outcome passed on to clients.
- around-style wrapping is the most general and allows the composer to
decide if and when to forward, and what result to return. It subsumes
before/after wrapping. This is what direct proxies currently provide.

As far as I can tell, virtual object abstractions like remote/persistent
objects require around-style wrapping, because there's otherwise no
meaningful target to automatically forward to.

Here's a list of use cases that I frequently have in mind when thinking
about proxies, categorized according to whether the use case requires
before/after/around wrapping:

Virtual objects, hence around-style:
- self-hosting exotic objects such as Date, Array (i.e. self-host an
ES5/ES6 environment)
- self-hosting DOM/WebIDL objects such as NodeList

Around-style wrapping (need to be able to change the result of an
operation):
- membranes
- higher-order contracts

Before-style wrapping:
- revocable references

What else?

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-11-28 Thread Brandon Benvie
Object.observe would fit under after correct?


On Wed, Nov 28, 2012 at 4:09 PM, Tom Van Cutsem tomvc...@gmail.com wrote:

 2012/11/26 Dean Tribble dtrib...@gmail.com

 On Mon, Nov 26, 2012 at 11:33 AM, Tom Van Cutsem tomvc...@gmail.comwrote:

 Thanks for spelling out these examples. While they still don't feel like
 actual important use cases to support, they give a good flavor of the kinds
 of compromises we'd need to make when turning to notification-only proxies.


 I agree. My usual expectation for proxies is to support remote and
 persistent objects. While supporting other scenarios is great, usually
 that's incidental.  Is there a broader list of aspirations for proxies? or
 is this just a all else being equal it would be good if we can do this?


 Let's talk about aspirations for proxies. It will help us set priorities.

 First, some terminology (originating from CLOS, the mother of all MOPs
 ;-)
 CLOS method combinations allow a composer to distinguish between before,
 after and around-style composition:
 - before-style wrapping gives you only the ability to get notified
 before an operation happens. You can abort, but not change, the result of
 the operation. This is what notification-proxies offer.
 - after-style wrapping allows you to get notified of an operation
 after-the-fact. Depending on the API, the after-wrapper may or may not
 get to see the outcome of the operation, and may or may not change the
 final outcome passed on to clients.
 - around-style wrapping is the most general and allows the composer to
 decide if and when to forward, and what result to return. It subsumes
 before/after wrapping. This is what direct proxies currently provide.

 As far as I can tell, virtual object abstractions like remote/persistent
 objects require around-style wrapping, because there's otherwise no
 meaningful target to automatically forward to.

 Here's a list of use cases that I frequently have in mind when thinking
 about proxies, categorized according to whether the use case requires
 before/after/around wrapping:

 Virtual objects, hence around-style:
 - self-hosting exotic objects such as Date, Array (i.e. self-host an
 ES5/ES6 environment)
 - self-hosting DOM/WebIDL objects such as NodeList

 Around-style wrapping (need to be able to change the result of an
 operation):
 - membranes
 - higher-order contracts

 Before-style wrapping:
 - revocable references

 What else?

 Cheers,
 Tom

 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss


___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-11-28 Thread David Bruant

Le 26/11/2012 21:39, David Bruant a écrit :

Le 26/11/2012 20:59, Tom Van Cutsem a écrit :

2012/11/26 David Bruant bruan...@gmail.com mailto:bruan...@gmail.com

We could define a symbolic value (like StopIteration for
iterators) that would mean forward to target. By essence of
what forwarding to the target means, there would be no need to
perform the least invariant check. We can call it ForwardToTarget :-)


I think we've previously entertained a similar proposal when a 
handler was encountering the .public property of a private property 
it didn't know, and then wanted to signal to the proxy I don't know 
this private name, please forward.
True. I had the feeling the idea wasn't entirely knew, but I couldn't 
recall what was the inspiration for it.


I recall one issue was that you'd really want a unique token per trap 
invocation, which costs.
I don't understand why a unique token per trap invocation would be 
necessary.

I still don't understand this point.
I've gone spelunking. I've found:
* the wiki page [1] (reflecting July meeting) which mentions that 
returning undefined would express I don't know the private name, please 
forward

* Confirmed on July 31st [2].
* Introduction of the idea of putting the verification of known names 
somewhere else than for each trap return [3]. Some discussion in between 
about this idea. Introduction of the idea of adding a third argument [4] 
after which I think stops all discussions about returning something in 
traps to prove knowledge of a private name or forwarding when not knowing.


I don't remember the point about a token per trap invocation and I 
haven't been able to find it (but I haven't read everything).


In any case, for throw ForwardToTarget, I don't see why it would be 
necessary. It seems it would work unambiguously with meta-handlers, with 
target-as-a-proxy or with manipulate-any-other-proxy-inside-a-trap 
(which target-as-a-proxy is an instance of).


David

[1] 
http://wiki.ecmascript.org/doku.php?id=harmony:direct_proxies#discussed_during_tc39_july_2012_meeting_microsoft_redmond

[2] https://mail.mozilla.org/pipermail/es-discuss/2012-July/024246.html
[3] https://mail.mozilla.org/pipermail/es-discuss/2012-July/024256.html
[4] https://mail.mozilla.org/pipermail/es-discuss/2012-August/024313.html
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-11-28 Thread Dean Tribble
On Wed, Nov 28, 2012 at 1:09 PM, Tom Van Cutsem tomvc...@gmail.com wrote:

 2012/11/26 Dean Tribble dtrib...@gmail.com

 ...
 I agree. My usual expectation for proxies is to support remote and
 persistent objects. While supporting other scenarios is great, usually
 that's incidental.  Is there a broader list of aspirations for proxies? or
 is this just a all else being equal it would be good if we can do this?


 Let's talk about aspirations for proxies. It will help us set priorities.
 First, some terminology (originating from CLOS, the mother of all MOPs
 ;-)


As a general point, I encourage you to look for other inspiration than CLOS
MOP for doign proxies (whose mother was really InterlispD). Meta-level
access deeply impacts security,maintainability,
reliability, understandability, etc. The tighter and more structured you
can make your meta-level access, the easier it will be to to implement,
use, and maintain (e.g., both coroutines and downward functions are more
understandable, easier to implement, easier to secure, etc. than general
continuations and call-cc).


 CLOS method combinations allow a composer to distinguish between before,
 after and around-style composition:
 - before-style wrapping gives you only the ability to get notified
 before an operation happens. You can abort, but not change, the result of
 the operation. This is what notification-proxies offer.


You *can* change the result of the operation. You do so by modifying the
state before the operation proceeds, of course. You could also extend the
notification support to notify after so you could clenup (avoiding a
callback hack).


 - after-style wrapping allows you to get notified of an operation
 after-the-fact. Depending on the API, the after-wrapper may or may not
 get to see the outcome of the operation, and may or may not change the
 final outcome passed on to clients.
 - around-style wrapping is the most general and allows the composer to
 decide if and when to forward, and what result to return. It subsumes
 before/after wrapping. This is what direct proxies currently provide.


It does not subsume before/after wrapping, because it loses the integrity
of before/after (e.g., the wrapper can lie and cheat, where the before and
after cannot).  That may be worth it, but it is substantially different.

Another variant is the differential version:  the differential trap is
like a notification, but it can also return virtual additions (or an
iterator of additions).  The proxy then invokes the primitive on the
target, and appends (with de-dupping, etc.) the virtual additions. This
allows the simple case to just use hte target, but also allows all of
Allen's additional cases.

 As far as I can tell, virtual object abstractions like remote/persistent
 objects require around-style wrapping, because there's otherwise no
 meaningful target to automatically forward to.


I thought the target in that case is an internal object to represent or
reify the meta-state of the remote or persistent object. I think that still
makes sense in both the persistent object and remote object cases.


 Here's a list of use cases that I frequently have in mind when thinking
 about proxies, categorized according to whether the use case requires
 before/after/around wrapping:

 Virtual objects, hence around-style:
 - self-hosting exotic objects such as Date, Array (i.e. self-host an
 ES5/ES6 environment)
 - self-hosting DOM/WebIDL objects such as NodeList


I should note that I'm not advocating a notification-only style for all
your proxy needs; having get operations able to generate virtual results
makes lots of sense. I primary suggest it for operations that are currently
implemented by the system (i.e., user code cannot normally intervene) and
that might be relied on for security-relevant behavior. wrapping return
results of user operations in a proxy makes perfect sense to me.


 Around-style wrapping (need to be able to change the result of an
 operation):
 - membranes
 - higher-order contracts

 Before-style wrapping:
 - revocable references


You can validate arguments, the state of the destination object (e.g., if
you were implementing a state machine), logging

 What else?


There is the pattern derived from the meter pattern in KeyKOS:  the handler
is only invoked on exception (e.g., like a page fault).  For example, a
primitive stream gets read operations against. Normally they proceed as a
primitive against an implementation-provided buffer so that next is
really darned fast. When the buffer is exhausted, instead of throwing an
error to the caller, the error is thrown to the handler (called a keeper)
which goes through some user-defined effort to refill the buffer, then the
read is retried.  This allows most data transfer to such a stream to use
fast, batch-oriented primitives, while supporting an arbitrary source of
contents.
___
es-discuss mailing list
es-discuss@mozilla.org

Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-11-28 Thread Allen Wirfs-Brock

On Nov 28, 2012, at 1:09 PM, Tom Van Cutsem wrote:

 2012/11/26 Dean Tribble dtrib...@gmail.com
 On Mon, Nov 26, 2012 at 11:33 AM, Tom Van Cutsem tomvc...@gmail.com wrote:
 Thanks for spelling out these examples. While they still don't feel like 
 actual important use cases to support, they give a good flavor of the kinds 
 of compromises we'd need to make when turning to notification-only proxies.
 
 I agree. My usual expectation for proxies is to support remote and persistent 
 objects. While supporting other scenarios is great, usually that's 
 incidental.  Is there a broader list of aspirations for proxies? or is this 
 just a all else being equal it would be good if we can do this?
 
 Let's talk about aspirations for proxies. It will help us set priorities.
 
 First, some terminology (originating from CLOS, the mother of all MOPs ;-)
 CLOS method combinations allow a composer to distinguish between before, 
 after and around-style composition:
 - before-style wrapping gives you only the ability to get notified before 
 an operation happens. You can abort, but not change, the result of the 
 operation. This is what notification-proxies offer.
 - after-style wrapping allows you to get notified of an operation 
 after-the-fact. Depending on the API, the after-wrapper may or may not get 
 to see the outcome of the operation, and may or may not change the final 
 outcome passed on to clients.
 - around-style wrapping is the most general and allows the composer to 
 decide if and when to forward, and what result to return. It subsumes 
 before/after wrapping. This is what direct proxies currently provide.
 
 As far as I can tell, virtual object abstractions like remote/persistent 
 objects require around-style wrapping, because there's otherwise no 
 meaningful target to automatically forward to.
 
 Here's a list of use cases that I frequently have in mind when thinking about 
 proxies, categorized according to whether the use case requires 
 before/after/around wrapping:
 
 Virtual objects, hence around-style:
 - self-hosting exotic objects such as Date, Array (i.e. self-host an 
 ES5/ES6 environment)
 - self-hosting DOM/WebIDL objects such as NodeList
-virtualizing a backing store as properties. 
-supported extended property attributes
 
 Around-style wrapping (need to be able to change the result of an operation):
 - membranes
 - higher-order contracts

introducing new inheritance schemes, eg, multiple inheritance

 
 Before-style wrapping:
 - revocable references

After-style

a doesNotUnderstand wrapper -- run the operation, but if the result is 
undefined check if missing property and if so, call  DNU handler


 
 What else?
 
 Cheers,
 Tom
 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-11-26 Thread David Bruant

Le 25/11/2012 15:32, Axel Rauschmayer a écrit :
If indeed both kinds of proxy are useful and direct proxies are more 
powerful, then why not only have a foundational direct proxy API and 
implement a tool type NotificationProxy that is based on that API.
An interesting question I still haven't found a satisfying answer to is: 
is the additional power of current proxies useful? and worth the cost? 
Because the current freedom of proxies is the root cause of invariant 
checks that even good proxy citizens have to pay.


David



[[[Sent from a mobile device. Please forgive brevity and typos.]]]

Dr. Axel Rauschmayer
a...@rauschma.de mailto:a...@rauschma.de
Home: http://rauschma.de
Blog: http://2ality.com

On 25.11.2012, at 12:44, Tom Van Cutsem tomvc...@gmail.com 
mailto:tomvc...@gmail.com wrote:



Hi,

I will refer to Dean's proposal as notification proxies (where 
traps essentially become notification callbacks), and will continue 
to use direct proxies for the current design where the trap can 
return a result (which is then verified).


These notification proxies remind me a lot of how one must implement 
membranes with direct proxies. The general idea here is that the 
proxy must use a shadow target as the proxy target, and the handler 
must refer to the real wrapped target. Traps that have to do with 
invariants (e.g. freeze/isFrozen, or querying a non-configurable 
property descriptor) require the proxy to synchronize the state of 
the real and shadow targets, because the proxy will verify the trap 
result against the shadow target.


For such membranes, let's consider how direct proxies and 
notification proxies trap an operation:


Direct proxies:
1) the proxy calls a trap on the handler
2) if the operation involves strong invariants on the real target, 
the handler must synchronize real and shadow target

3) the trap returns a result
4) if the proxy detects that the operation involves strong 
invariants, the trap result is verified against the shadow target


Notification proxies:
1) the proxy calls a trap on the handler (as a notification)
2) the handler must synchronize real and shadow target (regardless of 
whether invariants are involved)

3) the trap returns no result
4) the proxy performs the intercepted operation on the shadow and 
returns the result


I agree that the big benefit of notification proxies is that they get 
rid of all the complex validation logic.


However, some reservations:

- if traps become mere notifications, perhaps their names should 
change to reflect this, e.g. notifyGetOwnPropertyNames instead of 
getOwnPropertyNames. This is to alert handler writers that the 
return value of these traps will be ignored.


- I think we do lose some expressiveness in the case of pure virtual 
object abstractions that don't pretend to uphold any invariants.
With notification proxies, the handler must always (even in the case 
of configurable properties) define concrete properties on the target. 
Any virtual object abstraction is thus forced to maintain a shadow 
which must eventually be represented as a plain Javascript object.
In other words: *all* virtual object abstractions, whether they 
pretend to be frozen or not, have to make use of the shadow target 
technique, with the burden of synchronizing the shadow upon each 
operation. That burden currently doesn't exist for non-frozen virtual 
object abstractions (I'm using frozen vs non-frozen here as a 
shorthand for has non-configurable/non-extensible invariants vs 
has no such invariants).


- Regarding the overhead of the getOwnPropertyNames trap having to 
create a defensive copy of the trap result:

With notification proxies, upon trapping notifyGetOwnPropertyNames:
1) the trap must define all properties it wants to return on the 
target. If there are N properties, there is an O(N) physical storage 
cost involved.
2) the proxy applies the built-in Object.getOwnPropertyNames to the 
target. Assuming the target is a normal object, the primitive 
allocates a fresh array and returns the N properties.


In the current design:
1) the trap returns an array of property names (requiring O(N) 
physical storage cost)

2) the proxy copies and verifies this array

I think the storage costs are largely the same. However, with 
notification proxies, if the properties were virtual, those 
properties do linger as concrete properties on the target. Yes, the 
handler can delete them later, but when is later? Should the handler 
schedule clean-up actions using setTimeout(0)? This somehow does not 
feel right.


I like the simplicity of notification proxies, but we should think 
carefully what operations we turn into notifications only.


More generally, notification proxies are indeed 
even-more-direct-proxies. They make the wrapping use case 
(logging, profiling, contract checking, etc.) simpler, at the expense 
of virtual objects (remote objects, test mock-ups), which are 
forced to always concretize the virtual object's properties on a 
real 

Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-11-26 Thread David Bruant

Le 25/11/2012 12:44, Tom Van Cutsem a écrit :

(...)
I agree that the big benefit of notification proxies is that they get 
rid of all the complex validation logic.


However, some reservations:

(...)

- I think we do lose some expressiveness in the case of pure virtual 
object abstractions that don't pretend to uphold any invariants.

I don't think this is true. As Mark said:
The trick is that placing a configurable property on the target doesn't 
commit the handler to anything, since the handler can remove or change 
this property freely as of the next trap.

This is true for any trap I think.
I however agree that this 2-trap consistency may make the exercise of 
writing traps harder (but it'd take user testing to be 100% sure it's 
significantly harder).


I think there might be a loss in expressiveness if forwarding to the 
target throws an error. With current proxies, the trap can catch this 
exception; with notification proxies, the error is thrown after the 
trap, so it can't.
Now, it would require an in-depth analysis, but I intuit that all cases 
where an internal operation throws have a corresponding invariant checks 
(which errors aren't caught by current proxies). If that was the case, 
it would mean that there is actually no loss (or a minor loss consisting 
in loosing the ability to catch an error and rethrow it yourself)


Also, if you can only forward to target, there is no way you can define 
custom property descriptor attributes which would be a shame in my opinion.


With notification proxies, the handler must always (even in the case 
of configurable properties) define concrete properties on the target. 
Any virtual object abstraction is thus forced to maintain a shadow 
which must eventually be represented as a plain Javascript object.
I think that any virtual object abstraction which claims to maintain 
some sort of consistency has to store the necessary bits of this 
consistency somewhere. The target is as good as anywhere else.
I have to note that if the target is forced to be used as a regular 
object, then things like ProxyMap [1] become pointless (because the map 
is just used as a regular object, not as a map).



(...)
However, with notification proxies, if the properties were virtual, 
those properties do linger as concrete properties on the target. 
Yes, the handler can delete them later, but when is later? Should the 
handler schedule clean-up actions using setTimeout(0)? This somehow 
does not feel right.
According to Mark's comment, later is next trap. It's possible to 
maintain consistency, but writing the traps is a bit less easy.


I like the simplicity of notification proxies, but we should think 
carefully what operations we turn into notifications only.


More generally, notification proxies are indeed 
even-more-direct-proxies. They make the wrapping use case 
(logging, profiling, contract checking, etc.) simpler, at the expense 
of virtual objects (remote objects, test mock-ups), which are forced 
to always concretize the virtual object's properties on a real 
Javascript object.
I have what I think to be a interesting middleground allowing to bypass 
invariant checks while keeping direct proxies as they are.
My experience with writing traps with direct proxies is that traps (for 
non-virtual cases) almost all and always look like [2]:


trap: function(...args){
// do something

return Reflect.trap(...args); // or equivalent built-in/syntax
}

Let's take the Object.getOwnPropertyDescriptor trap as example. With 
current proxies, the trap would often end with 
Reflect.getOwnPropertyDescriptor(target, name) (or Object., whatev's), 
after the call on the target is finished, then, the engine checks the 
result against the target... but that's a bit dumb.
We know we wanted to get the target result and we made the most 
straightforward thing to do that guarantees invariants, but the engine 
still has to check, because it can't know the result comes from calling 
the Reflect operation on the target.
We could define a symbolic value (like StopIteration for iterators) that 
would mean forward to target. By essence of what forwarding to the 
target means, there would be no need to perform the least invariant 
check. We can call it ForwardToTarget :-)

Then traps involved in proxies preserving some consistency would look like:

trap: function(...args){
// do something

return ForwardToTarget;
}

The rule would become: if you want to do something simple, 
ForwardToTarget at the end of your trap and the invariant check cost is 
gone. If you want to use direct proxies freedom (virtual objects), you 
have to pay the cost of invariant checks to make sure you don't go too 
wild with your freedom


Best of both worlds for the cost of a symbol.

As a followup to my above comment about custom property descriptor 
attributes, it would be nice to be able to return something like 
ForwardToTargetAndCombineWith({custom1: val1, 

Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-11-26 Thread Sam Tobin-Hochstadt
On Mon, Nov 26, 2012 at 3:36 AM, David Bruant bruan...@gmail.com wrote:
 Le 25/11/2012 15:32, Axel Rauschmayer a écrit :

 If indeed both kinds of proxy are useful and direct proxies are more
 powerful, then why not only have a foundational direct proxy API and
 implement a tool type NotificationProxy that is based on that API.

 An interesting question I still haven't found a satisfying answer to is: is
 the additional power of current proxies useful? and worth the cost? Because
 the current freedom of proxies is the root cause of invariant checks that
 even good proxy citizens have to pay.

At a minimum, the direct proxies allow remote objects and other
entirely virtual objects to be implemented with no allocation
overhead.  In contrast, notification proxies require allocation
proportional to the size of the remote object being proxied. In
Racket, whose chaperone system has some of the flavor of notification
proxies, this makes remote objects more costly and difficult to
implement.  This is less of a problem in Racket, since the primary use
case for chaperones is the implementation of contracts, and virtual
objects would usually be handled differently.

--
sam th
sa...@ccs.neu.edu
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-11-26 Thread Allen Wirfs-Brock

On Nov 26, 2012, at 12:36 AM, David Bruant wrote:

 Le 25/11/2012 15:32, Axel Rauschmayer a écrit :
 If indeed both kinds of proxy are useful and direct proxies are more 
 powerful, then why not only have a foundational direct proxy API and 
 implement a tool type NotificationProxy that is based on that API.
 An interesting question I still haven't found a satisfying answer to is: is 
 the additional power of current proxies useful? and worth the cost? Because 
 the current freedom of proxies is the root cause of invariant checks that 
 even good proxy citizens have to pay.

One of the motivating use cases for Proxies is self-hosting exotic built-ins 
and host objects such as current Web API objects.  If the standard built-in 
Proxy abstraction isn't expressive enough for that job (and also efficient 
enough) then we haven't achieve the goal of supporting that use case.

If that happens what I suspect will happen is that some implementations will 
provide a non-standard, less restrictive, more expressive alternative to the 
standard Proxy.  That seems quite doable because it would just be another 
alternative exotic object  MOP binding for the engine to support.   I'd prefer 
that we provide a standard, interoperable abstraction rather than seeing 
non-interooperable solutions to this use case.

Allen






 
 David
 
 
 [[[Sent from a mobile device. Please forgive brevity and typos.]]]
 
 Dr. Axel Rauschmayer
 a...@rauschma.de
 Home: http://rauschma.de
 Blog: http://2ality.com
 
 On 25.11.2012, at 12:44, Tom Van Cutsem tomvc...@gmail.com wrote:
 
 Hi,
 
 I will refer to Dean's proposal as notification proxies (where traps 
 essentially become notification callbacks), and will continue to use 
 direct proxies for the current design where the trap can return a result 
 (which is then verified).
 
 These notification proxies remind me a lot of how one must implement 
 membranes with direct proxies. The general idea here is that the proxy must 
 use a shadow target as the proxy target, and the handler must refer to 
 the real wrapped target. Traps that have to do with invariants (e.g. 
 freeze/isFrozen, or querying a non-configurable property descriptor) 
 require the proxy to synchronize the state of the real and shadow 
 targets, because the proxy will verify the trap result against the shadow 
 target.
 
 For such membranes, let's consider how direct proxies and notification 
 proxies trap an operation:
 
 Direct proxies:
 1) the proxy calls a trap on the handler
 2) if the operation involves strong invariants on the real target, the 
 handler must synchronize real and shadow target
 3) the trap returns a result
 4) if the proxy detects that the operation involves strong invariants, the 
 trap result is verified against the shadow target
 
 Notification proxies:
 1) the proxy calls a trap on the handler (as a notification)
 2) the handler must synchronize real and shadow target (regardless of 
 whether invariants are involved)
 3) the trap returns no result
 4) the proxy performs the intercepted operation on the shadow and returns 
 the result
 
 I agree that the big benefit of notification proxies is that they get rid 
 of all the complex validation logic.
 
 However, some reservations:
 
 - if traps become mere notifications, perhaps their names should change to 
 reflect this, e.g. notifyGetOwnPropertyNames instead of 
 getOwnPropertyNames. This is to alert handler writers that the return 
 value of these traps will be ignored.
 
 - I think we do lose some expressiveness in the case of pure virtual object 
 abstractions that don't pretend to uphold any invariants.
 With notification proxies, the handler must always (even in the case of 
 configurable properties) define concrete properties on the target. Any 
 virtual object abstraction is thus forced to maintain a shadow which must 
 eventually be represented as a plain Javascript object.
 In other words: *all* virtual object abstractions, whether they pretend to 
 be frozen or not, have to make use of the shadow target technique, with 
 the burden of synchronizing the shadow upon each operation. That burden 
 currently doesn't exist for non-frozen virtual object abstractions (I'm 
 using frozen vs non-frozen here as a shorthand for has 
 non-configurable/non-extensible invariants vs has no such invariants).
 
 - Regarding the overhead of the getOwnPropertyNames trap having to create a 
 defensive copy of the trap result:
 With notification proxies, upon trapping notifyGetOwnPropertyNames:
 1) the trap must define all properties it wants to return on the target. If 
 there are N properties, there is an O(N) physical storage cost involved.
 2) the proxy applies the built-in Object.getOwnPropertyNames to the target. 
 Assuming the target is a normal object, the primitive allocates a fresh 
 array and returns the N properties.
 
 In the current design:
 1) the trap returns an array of property names (requiring O(N) physical 
 storage cost)
 2) the proxy 

Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-11-26 Thread David Bruant

Le 26/11/2012 19:58, Allen Wirfs-Brock a écrit :


On Nov 26, 2012, at 12:36 AM, David Bruant wrote:


Le 25/11/2012 15:32, Axel Rauschmayer a écrit :
If indeed both kinds of proxy are useful and direct proxies are more 
powerful, then why not only have a foundational direct proxy API and 
implement a tool type NotificationProxy that is based on that API.
An interesting question I still haven't found a satisfying answer to 
is: is the additional power of current proxies useful? and worth the 
cost? Because the current freedom of proxies is the root cause of 
invariant checks that even good proxy citizens have to pay.


One of the motivating use cases for Proxies is self-hosting exotic 
built-ins and host objects such as current Web API objects.  If the 
standard built-in Proxy abstraction isn't expressive enough for that 
job (and also efficient enough) then we haven't achieve the goal of 
supporting that use case.
I agree, but I haven't read evidence on the thread that notification 
proxies would have insufficient power to do so. In my other answer, I 
pointed to a couple of expressiveness (minor) losses, but nothing that 
would prevent self-hosting Web APIs. Do you have particular examples in 
mind?


David
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-11-26 Thread Tom Van Cutsem
2012/11/25 Allen Wirfs-Brock al...@wirfs-brock.com


 I have a couple virtual object use cases in mind where I don't think I
 would want to make all properties concrete on the target.


Thanks for spelling out these examples. While they still don't feel like
actual important use cases to support, they give a good flavor of the kinds
of compromises we'd need to make when turning to notification-only proxies.


 1) A bit vector abstraction where individual bits are accessible as
 numerically indexed properties.

 Assume I have a bit string of fairly large size (as little as 128 bits)
 and I would like to abstract it as an array of single bit numbers  where
 the indexes correspond to bit positions in the bit string.  Using Proxies I
 want be able to use Get and Put traps to direct such indexed access to a
 binary data backing store I maintain.  I believe that having to reify on
 the target each bit that is actually accessed  would be too  expensive in
 both time and space to justify using this approach.


Yes. As another example, consider a self-hosted sparse Array implementation.

The paradox here is that it's precisely those abstractions that seek to
store/retrieve properties in a more compact/efficient way than allowed by
the standard JS object model would turn to proxies, yet having to reify
each accessed property precisely voids the more compact/efficient storage
of properties.


 BTW, this is a scenario where I might not even brother trying to make sure
 that Object.getOwnPropertyNames listed all of the bit indexes.  I could,
 include them in an array of own property names, but would anybody really
 care if I didn't?


Well, yes and no.

Yes, in the sense that your object abstraction will break when used with
some tools and libraries. For instance, consider a debugger that uses
[[GetOwnPropertyNames]] to populate its inspector view, or a library that
contains generic algorithms that operate on arbitrary objects (say copying
an object, or serializing it, by using Object.getOwnPropertyNames).

No, in the sense that even if you would implement getOwnPropertyNames
consistently, copying or serializing your bit vector abstraction would not
lead to the desired result anyway (the copy or deserialized version would
be a normal object without the optimized bit representation) (although the
result might still be usable!)


 More generally, notification proxies are indeed
 even-more-direct-proxies. They make the wrapping use case (logging,
 profiling, contract checking, etc.) simpler, at the expense of virtual
 objects (remote objects, test mock-ups), which are forced to always
 concretize the virtual object's properties on a real Javascript object.


 Yes, I also like the simplicity of notification proxies but don't want to
 give up the power of virtual objects.  Maybe having both would be a
 reasonable alternative.


Brandon beat me to it, but indeed, having two kinds of proxies for the two
different use cases makes sense. Except that there's a complexity budget we
need to take into account. If we can avoid the cost of two APIs, we should.

Brandon's proposal tries to reduce the API bloat by keeping the exact same
API for both direct proxies and notification proxies, and changing the
rules dynamically based on the presence/absence of invariants. One issue I
have with that is that it will make it very hard for people writing proxies
to understand when the trap return value is ignored, and when it is not.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-11-26 Thread Brandon Benvie
There's a few goals I have in mind when thinking about proxies:
* Ability to forward to target at minimal cost.
* Minimal cost for invariant enforcement, preferably automatic since the
result is predetermined
* Near zero cost for invariant enforcement in the majority of cases where
it's not needed
* Ability to virtualize properties with minimal forced overhead (if someone
eagerly deep clones a membrane then that's their cost, not the API's)

When something becomes invariant, then the runtime essentially takes
ownership of it and it no longer belongs to the proxy. The proxy's only
remaining power is being the first to know whenever something is about to
happen. As the proxy creator, I don't really want to spend resources being
responsible for something I no longer have any control over.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-11-26 Thread Dean Tribble
I started to respond to Allan's message, but I'll combine them to here.
 Note the additional proposal in the middle of the message.

On Mon, Nov 26, 2012 at 11:33 AM, Tom Van Cutsem tomvc...@gmail.com wrote:

 2012/11/25 Allen Wirfs-Brock al...@wirfs-brock.com


 I have a couple virtual object use cases in mind where I don't think I
 would want to make all properties concrete on the target.


 Thanks for spelling out these examples. While they still don't feel like
 actual important use cases to support, they give a good flavor of the kinds
 of compromises we'd need to make when turning to notification-only proxies.


I agree. My usual expectation for proxies is to support remote and
persistent objects. While supporting other scenarios is great, usually
that's incidental.  Is there a broader list of aspirations for proxies? or
is this just a all else being equal it would be good if we can do this?



 1) A bit vector abstraction where individual bits are accessible as
 numerically indexed properties.

 Assume I have a bit string of fairly large size (as little as 128 bits)
 and I would like to abstract it as an array of single bit numbers  where
 the indexes correspond to bit positions in the bit string.  Using Proxies I
 want be able to use Get and Put traps to direct such indexed access to a
 binary data backing store I maintain.  I believe that having to reify on
 the target each bit that is actually accessed  would be too  expensive in
 both time and space to justify using this approach.


 Yes. As another example, consider a self-hosted sparse Array
 implementation.

 The paradox here is that it's precisely those abstractions that seek to
 store/retrieve properties in a more compact/efficient way than allowed by
 the standard JS object model would turn to proxies, yet having to reify
 each accessed property precisely voids the more compact/efficient storage
 of properties.


I don't have a good sense of how often and for what purpose clients call
getOwnPropertyNames and the like. That frankly seems like a terrible
operation for any client to be calling; it's architecturally necessarily
inefficient; especially since it currently demands a fresh array. Worst
case, I'd like to see it have a frozen result or be deprecated in favor of
an operation that is more architecturally efficient (e.g., return an
iterator of names so they need never all be reified). If the operation is
typically only called for debugging and inspection, or once per type or
some such, then the performance questions are less important. If libraries
constantly call it for web services, then having an improved API might be a
big win.

BTW, this is a scenario where I might not even brother trying to make sure
 that Object.getOwnPropertyNames listed all of the bit indexes.  I could,
 include them in an array of own property names, but would anybody really
 care if I didn't?


So for this example, you might want to suppress the integer properties from
getOwnPropertyNames *regardless *of the proxy approach. Otherwise you are
indeed doing O(N) work for all your otherwise efficiently-implemented bit
fields. Such a hack would work poorly with meta-driven tools (e.g.,
something that maps fields to a display table for object inspection), but
that's not because of the proxy support.

(It is conceivable to me that integer-indexed fields deserve explicit
support in a meta-protocol anyway, since their usage patterns are typically
so different from that of named fields.)


 Well, yes and no.

 Yes, in the sense that your object abstraction will break when used with
 some tools and libraries. For instance, consider a debugger that uses
 [[GetOwnPropertyNames]] to populate its inspector view, or a library that
 contains generic algorithms that operate on arbitrary objects (say copying
 an object, or serializing it, by using Object.getOwnPropertyNames).

 No, in the sense that even if you would implement getOwnPropertyNames
 consistently, copying or serializing your bit vector abstraction would not
 lead to the desired result anyway (the copy or deserialized version would
 be a normal object without the optimized bit representation) (although the
 result might still be usable!)


 More generally, notification proxies are indeed
 even-more-direct-proxies. They make the wrapping use case (logging,
 profiling, contract checking, etc.) simpler, at the expense of virtual
 objects (remote objects, test mock-ups), which are forced to always
 concretize the virtual object's properties on a real Javascript object.


 Yes, I also like the simplicity of notification proxies but don't want to
 give up the power of virtual objects.  Maybe having both would be a
 reasonable alternative.


 Brandon beat me to it, but indeed, having two kinds of proxies for the two
 different use cases makes sense. Except that there's a complexity budget we
 need to take into account. If we can avoid the cost of two APIs, we should.


I too would like to avoid two kinds of proxies. And 

Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-11-26 Thread David Bruant

Le 26/11/2012 20:59, Tom Van Cutsem a écrit :

2012/11/26 David Bruant bruan...@gmail.com mailto:bruan...@gmail.com

We could define a symbolic value (like StopIteration for
iterators) that would mean forward to target. By essence of what
forwarding to the target means, there would be no need to perform
the least invariant check. We can call it ForwardToTarget :-)


I think we've previously entertained a similar proposal when a handler 
was encountering the .public property of a private property it didn't 
know, and then wanted to signal to the proxy I don't know this 
private name, please forward.
True. I had the feeling the idea wasn't entirely knew, but I couldn't 
recall what was the inspiration for it.


I recall one issue was that you'd really want a unique token per trap 
invocation, which costs.
I don't understand why a unique token per trap invocation would be 
necessary.


By the way, very much like for iterators, it would have to be throw 
ForwardToTarget instead of return ForwardToTarget because the symbol 
could be a value people would want to return while it would be a bad 
practice to expect a specific value to be thrown in a normal execution.


David
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-11-25 Thread Tom Van Cutsem
Hi,

I will refer to Dean's proposal as notification proxies (where traps
essentially become notification callbacks), and will continue to use
direct proxies for the current design where the trap can return a result
(which is then verified).

These notification proxies remind me a lot of how one must implement
membranes with direct proxies. The general idea here is that the proxy must
use a shadow target as the proxy target, and the handler must refer to
the real wrapped target. Traps that have to do with invariants (e.g.
freeze/isFrozen, or querying a non-configurable property descriptor)
require the proxy to synchronize the state of the real and shadow
targets, because the proxy will verify the trap result against the shadow
target.

For such membranes, let's consider how direct proxies and notification
proxies trap an operation:

Direct proxies:
1) the proxy calls a trap on the handler
2) if the operation involves strong invariants on the real target, the
handler must synchronize real and shadow target
3) the trap returns a result
4) if the proxy detects that the operation involves strong invariants, the
trap result is verified against the shadow target

Notification proxies:
1) the proxy calls a trap on the handler (as a notification)
2) the handler must synchronize real and shadow target (regardless of
whether invariants are involved)
3) the trap returns no result
4) the proxy performs the intercepted operation on the shadow and returns
the result

I agree that the big benefit of notification proxies is that they get rid
of all the complex validation logic.

However, some reservations:

- if traps become mere notifications, perhaps their names should change to
reflect this, e.g. notifyGetOwnPropertyNames instead of
getOwnPropertyNames. This is to alert handler writers that the return
value of these traps will be ignored.

- I think we do lose some expressiveness in the case of pure virtual object
abstractions that don't pretend to uphold any invariants.
With notification proxies, the handler must always (even in the case of
configurable properties) define concrete properties on the target. Any
virtual object abstraction is thus forced to maintain a shadow which must
eventually be represented as a plain Javascript object.
In other words: *all* virtual object abstractions, whether they pretend to
be frozen or not, have to make use of the shadow target technique, with
the burden of synchronizing the shadow upon each operation. That burden
currently doesn't exist for non-frozen virtual object abstractions (I'm
using frozen vs non-frozen here as a shorthand for has
non-configurable/non-extensible invariants vs has no such invariants).

- Regarding the overhead of the getOwnPropertyNames trap having to create a
defensive copy of the trap result:
With notification proxies, upon trapping notifyGetOwnPropertyNames:
1) the trap must define all properties it wants to return on the target. If
there are N properties, there is an O(N) physical storage cost involved.
2) the proxy applies the built-in Object.getOwnPropertyNames to the target.
Assuming the target is a normal object, the primitive allocates a fresh
array and returns the N properties.

In the current design:
1) the trap returns an array of property names (requiring O(N) physical
storage cost)
2) the proxy copies and verifies this array

I think the storage costs are largely the same. However, with notification
proxies, if the properties were virtual, those properties do linger as
concrete properties on the target. Yes, the handler can delete them
later, but when is later? Should the handler schedule clean-up actions
using setTimeout(0)? This somehow does not feel right.

I like the simplicity of notification proxies, but we should think
carefully what operations we turn into notifications only.

More generally, notification proxies are indeed even-more-direct-proxies.
They make the wrapping use case (logging, profiling, contract checking,
etc.) simpler, at the expense of virtual objects (remote objects, test
mock-ups), which are forced to always concretize the virtual object's
properties on a real Javascript object.

Cheers,
Tom

2012/11/25 Mark S. Miller erig...@google.com

 +1. I think this is a really effective extension of the direct proxy
 approach, and I don't know why we didn't see it earlier. It's weird
 that this preserves all the flexibility of fully virtual configurable
 properties even though it insists that even these be made into real
 properties on the target. The trick is that placing a configurable
 property on the target doesn't commit the handler to anything, since
 the handler can remove or change this property freely as of the next
 trap.

 Apologies again for not yet having the time to do more than skim the
 thread at this point. But IIRC someone already suggested a similar
 change to some of the imperative traps -- perhaps freeze, seal, and
 preventExtensions. The handler would not perform these operations on
 the target, only to 

Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-11-25 Thread Brandon Benvie
I think it could be argued that the two categories of proxy uses have
different enough fundamentals that they would be better suited broken into
two separate types of proxies. They use a common protocol for dispatching
notifications/requests, but the result is incompatible.

For a Notification Proxy the trap is notified and then action proceeds
against the ProxyTarget as it would normally. This is the simple case since
it merely adds a pre-notification to the front of all trapped operations
and nothing else changes.

For a Virtual Proxy the invariant-sensitive attributes of the virtual
target act like those of a Notification Proxy. Any time something becomes
invariant, whether it be a property or the whole object, the value is
reified from being virtual to being an actual property. From that point on
the property or the whole Proxy changes behavior from Virtual to
Notification.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-11-25 Thread Axel Rauschmayer
If indeed both kinds of proxy are useful and direct proxies are more powerful, 
then why not only have a foundational direct proxy API and implement a tool 
type NotificationProxy that is based on that API.


[[[Sent from a mobile device. Please forgive brevity and typos.]]]

Dr. Axel Rauschmayer
a...@rauschma.de
Home: http://rauschma.de
Blog: http://2ality.com

On 25.11.2012, at 12:44, Tom Van Cutsem tomvc...@gmail.com wrote:

 Hi,
 
 I will refer to Dean's proposal as notification proxies (where traps 
 essentially become notification callbacks), and will continue to use direct 
 proxies for the current design where the trap can return a result (which is 
 then verified).
 
 These notification proxies remind me a lot of how one must implement 
 membranes with direct proxies. The general idea here is that the proxy must 
 use a shadow target as the proxy target, and the handler must refer to the 
 real wrapped target. Traps that have to do with invariants (e.g. 
 freeze/isFrozen, or querying a non-configurable property descriptor) require 
 the proxy to synchronize the state of the real and shadow targets, because 
 the proxy will verify the trap result against the shadow target.
 
 For such membranes, let's consider how direct proxies and notification 
 proxies trap an operation:
 
 Direct proxies:
 1) the proxy calls a trap on the handler
 2) if the operation involves strong invariants on the real target, the 
 handler must synchronize real and shadow target
 3) the trap returns a result
 4) if the proxy detects that the operation involves strong invariants, the 
 trap result is verified against the shadow target
 
 Notification proxies:
 1) the proxy calls a trap on the handler (as a notification)
 2) the handler must synchronize real and shadow target (regardless of whether 
 invariants are involved)
 3) the trap returns no result
 4) the proxy performs the intercepted operation on the shadow and returns the 
 result
 
 I agree that the big benefit of notification proxies is that they get rid of 
 all the complex validation logic.
 
 However, some reservations:
 
 - if traps become mere notifications, perhaps their names should change to 
 reflect this, e.g. notifyGetOwnPropertyNames instead of 
 getOwnPropertyNames. This is to alert handler writers that the return value 
 of these traps will be ignored.
 
 - I think we do lose some expressiveness in the case of pure virtual object 
 abstractions that don't pretend to uphold any invariants.
 With notification proxies, the handler must always (even in the case of 
 configurable properties) define concrete properties on the target. Any 
 virtual object abstraction is thus forced to maintain a shadow which must 
 eventually be represented as a plain Javascript object.
 In other words: *all* virtual object abstractions, whether they pretend to be 
 frozen or not, have to make use of the shadow target technique, with the 
 burden of synchronizing the shadow upon each operation. That burden currently 
 doesn't exist for non-frozen virtual object abstractions (I'm using frozen 
 vs non-frozen here as a shorthand for has non-configurable/non-extensible 
 invariants vs has no such invariants).
 
 - Regarding the overhead of the getOwnPropertyNames trap having to create a 
 defensive copy of the trap result:
 With notification proxies, upon trapping notifyGetOwnPropertyNames:
 1) the trap must define all properties it wants to return on the target. If 
 there are N properties, there is an O(N) physical storage cost involved.
 2) the proxy applies the built-in Object.getOwnPropertyNames to the target. 
 Assuming the target is a normal object, the primitive allocates a fresh array 
 and returns the N properties.
 
 In the current design:
 1) the trap returns an array of property names (requiring O(N) physical 
 storage cost)
 2) the proxy copies and verifies this array
 
 I think the storage costs are largely the same. However, with notification 
 proxies, if the properties were virtual, those properties do linger as 
 concrete properties on the target. Yes, the handler can delete them later, 
 but when is later? Should the handler schedule clean-up actions using 
 setTimeout(0)? This somehow does not feel right.
 
 I like the simplicity of notification proxies, but we should think carefully 
 what operations we turn into notifications only.
 
 More generally, notification proxies are indeed even-more-direct-proxies. 
 They make the wrapping use case (logging, profiling, contract checking, 
 etc.) simpler, at the expense of virtual objects (remote objects, test 
 mock-ups), which are forced to always concretize the virtual object's 
 properties on a real Javascript object.
 
 Cheers,
 Tom
 
 2012/11/25 Mark S. Miller erig...@google.com
 +1. I think this is a really effective extension of the direct proxy
 approach, and I don't know why we didn't see it earlier. It's weird
 that this preserves all the flexibility of fully virtual configurable
 properties even 

Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-11-25 Thread Allen Wirfs-Brock
On Nov 25, 2012, at 4:15 AM, Brandon Benvie wrote:

 I think it could be argued that the two categories of proxy uses have 
 different enough fundamentals that they would be better suited broken into 
 two separate types of proxies. They use a common protocol for dispatching 
 notifications/requests, but the result is incompatible.
 
 For a Notification Proxy the trap is notified and then action proceeds 
 against the ProxyTarget as it would normally. This is the simple case since 
 it merely adds a pre-notification to the front of all trapped operations and 
 nothing else changes.
 
 For a Virtual Proxy the invariant-sensitive attributes of the virtual target 
 act like those of a Notification Proxy. Any time something becomes invariant, 
 whether it be a property or the whole object, the value is reified from being 
 virtual to being an actual property. From that point on the property or the 
 whole Proxy changes behavior from Virtual to Notification. 

And using the new specification MOP this would be quite easy to specify. I even 
suspect that it would be fairly easy to implement, assuming that engines 
actually dynamically dispatch internal method calls at approximately the 
granularity of those specified by the MOP.

I actually had the thought as I was working through the MOP and the Proxy 
internal methods, that I'd wager that somebody is going to come up with other 
proxy like abstractions that are optimized for different scenarios and that 
they'd eventually get implemented.

Allen













 ___
 es-discuss mailing list
 es-discuss@mozilla.org
 https://mail.mozilla.org/listinfo/es-discuss

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-11-25 Thread Allen Wirfs-Brock

On Nov 25, 2012, at 3:44 AM, Tom Van Cutsem wrote:

 Hi,
 
 I will refer to Dean's proposal as notification proxies (where traps 
 essentially become notification callbacks), and will continue to use direct 
 proxies for the current design where the trap can return a result (which is 
 then verified).

I agree with Mark that Dean has a quite clever proposal...

...

 
 However, some reservations:

me too...although I think notification proxies are optimized for a real use 
case and might be worth supporting.


 
 - if traps become mere notifications, perhaps their names should change to 
 reflect this, e.g. notifyGetOwnPropertyNames instead of 
 getOwnPropertyNames. This is to alert handler writers that the return value 
 of these traps will be ignored.
 
 - I think we do lose some expressiveness in the case of pure virtual object 
 abstractions that don't pretend to uphold any invariants.
 With notification proxies, the handler must always (even in the case of 
 configurable properties) define concrete properties on the target. Any 
 virtual object abstraction is thus forced to maintain a shadow which must 
 eventually be represented as a plain Javascript object.
 In other words: *all* virtual object abstractions, whether they pretend to be 
 frozen or not, have to make use of the shadow target technique, with the 
 burden of synchronizing the shadow upon each operation. That burden currently 
 doesn't exist for non-frozen virtual object abstractions (I'm using frozen 
 vs non-frozen here as a shorthand for has non-configurable/non-extensible 
 invariants vs has no such invariants).

I have a couple virtual object use cases in mind where I don't think I would 
want to make all properties concrete on the target.

1) A bit vector abstraction where individual bits are accessible as numerically 
indexed properties. 

Assume I have a bit string of fairly large size (as little as 128 bits) and I 
would like to abstract it as an array of single bit numbers  where the indexes 
correspond to bit positions in the bit string.  Using Proxies I want be able to 
use Get and Put traps to direct such indexed access to a binary data backing 
store I maintain.  I believe that having to reify on the target each bit that 
is actually accessed  would be too  expensive in both time and space to justify 
using this approach.

BTW, this is a scenario where I might not even brother trying to make sure that 
Object.getOwnPropertyNames listed all of the bit indexes.  I could, include 
them in an array of own property names, but would anybody really care if I 
didn't?  

2)  Multiple Inheritance

I'm playing with what it takes to support self-like multiple inheritance using 
proxies. One approach that looks promising is to use a Proxy-based object as 
the immediate [[Prototype]] of leaf objects that have multiple logical 
inheritance parents.  That lets put/gets of own property operate at native 
speed and the Put/Get handlers only get invoked for inherited properties.  The 
MI parent proxy keeps track (using its own private state) of the multiple 
parents and doesn't really use it own [[Prototype]] ( actually it's target 
object's [[Prototype]]) as a lookup path for proto climbing.  It encapsulates 
this entire mechanism such that from the perspective of the leaf object, all of 
its inherited properties look like own properties of the MI parent proxy.   I 
would hate to have to copy down every accessed inherited property.  There are 
situations were I might want to copy down some of them, but probably not all.


 ...
 I think the storage costs are largely the same. However, with notification 
 proxies, if the properties were virtual, those properties do linger as 
 concrete properties on the target. Yes, the handler can delete them later, 
 but when is later? Should the handler schedule clean-up actions using 
 setTimeout(0)? This somehow does not feel right.

Yes indeed.  Storage cost may be comparable for getOwnProperyNames that that is 
presumably a rare operation. If all traps had that characteristic I think many 
virtual object use cases would be too expensive to make the practical. 

 
 I like the simplicity of notification proxies, but we should think carefully 
 what operations we turn into notifications only.
 
 More generally, notification proxies are indeed even-more-direct-proxies. 
 They make the wrapping use case (logging, profiling, contract checking, 
 etc.) simpler, at the expense of virtual objects (remote objects, test 
 mock-ups), which are forced to always concretize the virtual object's 
 properties on a real Javascript object.

Yes, I also like the simplicity of notification proxies but don't want to give 
up the power of virtual objects.  Maybe having both would be a reasonable 
alternative.

Allen







 
 Cheers,
 Tom
 
 2012/11/25 Mark S. Miller erig...@google.com
 +1. I think this is a really effective extension of the direct proxy
 approach, and I don't know why we didn't see it earlier. It's weird
 

Re: Notification proxies (Was: possible excessive proxy invariants for Object.keys/etc??)

2012-11-25 Thread Allen Wirfs-Brock

On Nov 25, 2012, at 6:32 AM, Axel Rauschmayer wrote:

 If indeed both kinds of proxy are useful and direct proxies are more 
 powerful, then why not only have a foundational direct proxy API and 
 implement a tool type NotificationProxy that is based on that API.
 

That might work.  In that case you would probably do no invariant enforcement 
in the direct proxy internal methods and the notification proxy APIs would 
supply an intermediate layer of traps that called notification traps and then 
delegated to the target to get the actual results...

Allen

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-24 Thread Dean Tribble
I am looking forward to proxies in JavaScript, and had a thought on the
issues below.  You could extend the the direct proxy approach for this.

When the Proxy receives getOwnPropertyNames, it
1) notifies the handler that property names are being requested
2) the handler adds/removes any properties (configurable or otherwise
subject to the normal constraints) on the target
3) upon return, the proxy invokes getOwnPropertyNames directly on the
target (e..g, invoking the *normal *system primitive)

This approach appears to have consistent behavior for configurability and
extensibility. For example, the trap operation above could add configurable
properties to an extensible target, and remove them later.  It could add
non-configurable properties, but they are permanent once added, etc. Thus
there's no loss of generality.  In addition to optionally setting up
properties on the target, the handler trap above would need to indicate to
the proxy (via exception or boolean result) that the getOwnPropertyNames
operation should proceed ahead or fail.

This extension of the direct proxy approach applies to all query
operations, eliminates the copying and validation overhead discussed below,
simplifies the implementation, retains full backwards compatibility, and
enables most if not all the expressiveness we might expect for proxies.

Dean

From: Allen Wirfs-Brock al...@wirfs-brock.com
 Date: Tue, Nov 20, 2012 at 2:18 PM
 Subject: Fwd: possible excessive proxy invariants for Object.keys/etc??
 To: es-discuss discussion es-discuss@mozilla.org


 Tom Van Custem have been having some email discussion while I work on
 integrating Proxys into the ES6 spec.  He and I agree that some
 broader input would be useful so I'm going to forward some of the
 message here to es-discuss and carry the discussion forward here.
 Here is the first message with other to follow:

 Begin forwarded message:

 From: Allen Wirfs-Brock al...@wirfs-brock.com
 Date: November 18, 2012 1:26:14 PM PST
 To: Tom Van Cutsem tomvc...@gmail.com, Mark S. Miller 
 erig...@google.com
 Cc: Jason Orendorff jorendo...@mozilla.com
 Subject: possible excessive proxy invariants for Object.keys/etc??

 I'm wondering if the wiki spec. for these functions aren't doing
 invariant checking that goes beyond what is required for the integrity
 purposes you have stated.

 In general, proxies  traps check to ensure that the invariants of a
 sealed/frozen target object aren't violated.  Generally, only minimal
 processing needs to be done if the target is extensible and has no
 non-configurable properties.  In fact the Virtual Object proposal says
 As long as the proxy does not expose non-configurable properties or
 becomes non-extensible, the target object is fully ignored (except to
 acquire internal properties such as [[Class]]). .

 The proxy spec.for Object.getOwnPropertyNames/kets/etc. seem to be
 doing quite a bit more than this.  They

 1) always copy the array returned from the trap?  Why is this
 necessary?  Sure the author of a trap should probably always return a
 fresh object but not doing so doesn't violate the integrity of the
 frozen/sealed invariants?  In most cases they will provide a fresh
 object and  copying adds unnecessary  work  that is proportional to
 the number of names to every such call.

 2) ensuring that the list of property keys contains no duplicates.
 Why is this essential?  Again, I don't see what it has to do with the
 integrity of the frozen/sealed invariants.  It is extra and probably
 unnecessary work that is at least proportional to the number of
 names).

 3) Every name in the list returned by the trap code is looked up on
 the target to determine whether or not it exists, even if the target
 is extensible.   Each of those lookup is observable (the target might
 itself be a proxy) so, according to the algorithm they all must be
 performed.

 4) Every own property of the target, is observably looked up (possibly
 a second time) even if the object is extensible  and has no
 non-configurable properties.


 It isn't clear to me if any of this work is really necessary to ensure
 integrity.  After all, what can you do with any of these names other
 than use them as the property key argument to some other trap/internal
 method such as [[SetP]], [[DefineOwnProperty]], etc.  Called on a
 proxy, those fundamental operations are going to enforce the integrity
 invariants of the actual properties involved so the get name checks
 doesn't really seem to be adding anything essential.

 Perhaps we can just get rid of all the above checking.  It seems like
 a good idea to me.

 Alternatively,  it suggests that a [[GetNonConfigurablePropertyNames]]
 internal method/trap would be a useful call to have as the integrity
 invariants only care about non-configurable properties. That would
 significantly limit the work in the case where there are none and
 limit the observable trap calls to only the non-configurable
 properties.

 Allen

Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-24 Thread Mark S. Miller
+1. I think this is a really effective extension of the direct proxy
approach, and I don't know why we didn't see it earlier. It's weird
that this preserves all the flexibility of fully virtual configurable
properties even though it insists that even these be made into real
properties on the target. The trick is that placing a configurable
property on the target doesn't commit the handler to anything, since
the handler can remove or change this property freely as of the next
trap.

Apologies again for not yet having the time to do more than skim the
thread at this point. But IIRC someone already suggested a similar
change to some of the imperative traps -- perhaps freeze, seal, and
preventExtensions. The handler would not perform these operations on
the target, only to have the proxy check it. Rather, if the trap
indicates that the operation should succeed, the proxy then simply
performs the operation -- or else throws. I wonder if this philosophy
could be extended to some of the other imperative operations as well?

What expressiveness does this even-more-direct proxy approach lose?
AFAICT, not much. At the same time, it should result in a *much*
simpler implementation and much greater confidence that invariants of
the non-proxy sublanguage are preserved by the introduction of
proxies. In fact, I think it's much stronger on invariant preservation
that the current direct proxies, while being much simpler.


On Sat, Nov 24, 2012 at 6:49 PM, Dean Tribble dtrib...@gmail.com wrote:
 I am looking forward to proxies in JavaScript, and had a thought on the
 issues below.  You could extend the the direct proxy approach for this.

 When the Proxy receives getOwnPropertyNames, it
 1) notifies the handler that property names are being requested
 2) the handler adds/removes any properties (configurable or otherwise
 subject to the normal constraints) on the target
 3) upon return, the proxy invokes getOwnPropertyNames directly on the target
 (e..g, invoking the normal system primitive)

 This approach appears to have consistent behavior for configurability and
 extensibility. For example, the trap operation above could add configurable
 properties to an extensible target, and remove them later.  It could add
 non-configurable properties, but they are permanent once added, etc. Thus
 there's no loss of generality.  In addition to optionally setting up
 properties on the target, the handler trap above would need to indicate to
 the proxy (via exception or boolean result) that the getOwnPropertyNames
 operation should proceed ahead or fail.

 This extension of the direct proxy approach applies to all query
 operations, eliminates the copying and validation overhead discussed below,
 simplifies the implementation, retains full backwards compatibility, and
 enables most if not all the expressiveness we might expect for proxies.

 Dean

 From: Allen Wirfs-Brock al...@wirfs-brock.com
 Date: Tue, Nov 20, 2012 at 2:18 PM
 Subject: Fwd: possible excessive proxy invariants for Object.keys/etc??
 To: es-discuss discussion es-discuss@mozilla.org


 Tom Van Custem have been having some email discussion while I work on
 integrating Proxys into the ES6 spec.  He and I agree that some
 broader input would be useful so I'm going to forward some of the
 message here to es-discuss and carry the discussion forward here.
 Here is the first message with other to follow:

 Begin forwarded message:

 From: Allen Wirfs-Brock al...@wirfs-brock.com
 Date: November 18, 2012 1:26:14 PM PST
 To: Tom Van Cutsem tomvc...@gmail.com, Mark S. Miller
 erig...@google.com
 Cc: Jason Orendorff jorendo...@mozilla.com
 Subject: possible excessive proxy invariants for Object.keys/etc??

 I'm wondering if the wiki spec. for these functions aren't doing
 invariant checking that goes beyond what is required for the integrity
 purposes you have stated.

 In general, proxies  traps check to ensure that the invariants of a
 sealed/frozen target object aren't violated.  Generally, only minimal
 processing needs to be done if the target is extensible and has no
 non-configurable properties.  In fact the Virtual Object proposal says
 As long as the proxy does not expose non-configurable properties or
 becomes non-extensible, the target object is fully ignored (except to
 acquire internal properties such as [[Class]]). .

 The proxy spec.for Object.getOwnPropertyNames/kets/etc. seem to be
 doing quite a bit more than this.  They

 1) always copy the array returned from the trap?  Why is this
 necessary?  Sure the author of a trap should probably always return a
 fresh object but not doing so doesn't violate the integrity of the
 frozen/sealed invariants?  In most cases they will provide a fresh
 object and  copying adds unnecessary  work  that is proportional to
 the number of names to every such call.

 2) ensuring that the list of property keys contains no duplicates.
 Why is this essential?  Again, I don't see what it has to do with the
 integrity of the frozen

Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-22 Thread Tom Van Cutsem
2012/11/21 Allen Wirfs-Brock al...@wirfs-brock.com


 On Nov 21, 2012, at 12:09 PM, Tom Van Cutsem wrote:

 Let's first discuss whether there is an issue with just letting (unique)
 symbols show up in Object.{keys,getOwnPropertyNames}.
 It's still a change in return type (from Array[String] to
 Array[String|Symbol]), but a far less innocuous one than changing
 Array[String] into Any.


 Wow, I actually think that the Array[String|Symbol] change is far more
 likely to have actual compatibility impact.  I can imagine various
 scenarios where is program or library is doing string processing on the
 elements returned from keys/getOPN.  That seems far more likely, then that
 they have dependencies upon the returned collection being Array.isArray
 rather than just Array-like.


If we don't do any invariant checks, the trap isn't even obliged to return
an array-like. Code that expects an array-like is likely to immediately
crash if this happens though, so I'm not sure if that's a real issue.





 c) to ensure the stability of the result.

 You can think of a + b as implementing a type coercion of the trap
 result to Array of String. This coercion is not too dissimilar from what
 the getOwnPropertyDescriptor has to do (normalization of the returned
 property descriptor by creating a fresh copy).


 Yes, premature type coercion, in my opinion. Also, a classic performance
 mistakes made by dynamic language programmers:  unnecessary coercion of
 values that are never going to be access or redundant coercion checks of
 values that are already of the property type.  Why is it important to do
 such checks on values that are are just passing through these traps.  When
 and if somebody actually gets arounds to using one of the elements that are
 returned as a property key they will be automatically coerced to a valid
 value.  Why is it important that it happens any sooner than that.


 I don't know if you are familiar with the work of Felleisen et al. on
 higher-order contracts. In that work, they use the notion of blame
 between different components/modules. Basically: if some module A receives
 some data from a module B, and B provides wrong data, then B should be
 assigned blame. You don't want to end up in a situation where A receives
 the blame at the point where it passes that wrong data into another
 module C.


 Yes, but ES is rampant with this sort of potentially misplaced blame.  We
 can debate whether such proper blame assignment is important or not, but
 I do believe this sort of very low level MOP interface is a situation where
 you want to absolutely minimize none essential work.  I'd sooner have it be
 a little bit more difficult to track now Proxy based bugs then to impact
 the performance of every correctly implemented proxy in every correct
 program. BTW this is a general statement about the entire proxy MOP and not
 just about these particularly property key access traps.


 It's true that most proxies will probably be benign and thus most dynamic
 invariant checks will succeed. But we should not remove checks just because
 they succeed 99.9% of the time. By analogy, most arguments passed to the +
 operator are valid operands, but that doesn't obviate the runtime
 type-check it must make over and over again (barring optimization). In the
 case of the + operator a forgotten type-check would lead to a crash or
 memory-unsafe behavior. In the case of a forgotten invariant check for
 proxies, the consequences are far less severe, but may lead to inconsistent
 behavior none the less.

 There is a big difference between essential checks that are needed for
 memory safety and checks that are needed to maintain some of these proxy
 invariants.  As you say, one will cause system level crashes or unsafe
 memory accesses.  The other just introduces application level bugs.

 Essential runtime checks are always should be designed to be as
 inexpensive as possible and for that reason are always very simple.
  Complex relationship validation belongs at the application level.  You
 might do such validation in your sandbox implementation (for example
 providing your own Object.getOwnPropertyNames that does a copy to a fresh
 array) but it shouldn't be forced upon applications that don't need it.



 The early type coercions at the exit of the traps can be thought of in
 these terms: the invariant checks will always blame the proxy handler for
 producing wrong data, at the point where the wrong data is produced and
 before it's exposed to client code. Clients are expecting ES5/6 objects to
 obey an implicit contract.


 We are defining that contract right now. It would be a mistake to over
 specify it in ways that may unnecessarily impact performance.




 getOwnPropertyDescriptor is also on my list to talk to you about for
 similar reasons.  I don't see why the property descriptor needs to be
 normalized and regenerated (including converting accessor properties on the
 descriptor into data properties and requiring the 

Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-22 Thread Allen Wirfs-Brock

On Nov 22, 2012, at 5:36 AM, Tom Van Cutsem wrote:

 2012/11/21 Allen Wirfs-Brock al...@wirfs-brock.com
 
 On Nov 21, 2012, at 12:09 PM, Tom Van Cutsem wrote:
 Let's first discuss whether there is an issue with just letting (unique) 
 symbols show up in Object.{keys,getOwnPropertyNames}.
 It's still a change in return type (from Array[String] to 
 Array[String|Symbol]), but a far less innocuous one than changing 
 Array[String] into Any.
 
 Wow, I actually think that the Array[String|Symbol] change is far more likely 
 to have actual compatibility impact.  I can imagine various scenarios where 
 is program or library is doing string processing on the elements returned 
 from keys/getOPN.  That seems far more likely, then that they have 
 dependencies upon the returned collection being Array.isArray rather than 
 just Array-like.
 
 If we don't do any invariant checks, the trap isn't even obliged to return an 
 array-like. Code that expects an array-like is likely to immediately crash if 
 this happens though, so I'm not sure if that's a real issue.

Just like all the generic array function.  Essentially all objects are 
array-like, you don't even need to have a length property.  Such 
array-likes generally act as if they had a length of 0.

Alternatively, what's the real difference to an application whether it 
crashes  (eg, throws TypeError) within the Proxy implementation of [[Keys]] 
or crashes when it touches the object returned from Object.keys? 

...

 
 A concrete example: say I'm implementing a membrane that wants to allow 
 frozen records to pass through the membrane unwrapped.
 By record, I mean an object with only data properties bound to primitives 
 (strings, numbers, ...). Since individual strings and numbers can pass 
 through unwrapped, it's not entirely unreasonable to allow compound values 
 composed of only primitives to be passed through unwrapped as well.
 
 To pass such frozen records, the membrane needs to perform a check to see 
 whether the frozen object is indeed a record.
 To do so, it must be able to iterate over all the properties of the object 
 and test whether they are indeed data properties bound to primitives.
 
 If the frozen record is a proxy that can lie about its own properties, it can 
 not report a particular foo property that is bound to a mutable object, 
 thus opening a communications channel piercing the membrane.
  
 ...

 Hence my above question, is getOPN really one of these basic primitives?
 
 Without at least 1 operation that reliably lists an object's properties, you 
 can't reliably introspect a frozen object.
 
  ...

 It still appears to me that for Sealed/Frozen objects, which I believe are 
 the ones you actually care about, you are enforcing that the list returned is 
 exactly the own properties of the ultimate ordinary target object (perhaps 
 with multiple levels of proxy indirection).  In otherwords, the result cannot 
 be meaningfully changed.  In that case it doesn't need to be trap.
 
 You're right that the result cannot be meaningfully changed for frozen 
 objects. But it still needs to be a trap for membranes. The issue is again 
 that the membrane proxy needs to be notified of the operation occurring, so 
 that it can update its target object before the operation proceeds. Like 
 Brandon mentioned earlier in this thread, the trap is effectively just a 
 notification callback at that point.
 

Then I think the thing to do is provide a [[GetNonConfigurablePropertyKeys]] 
internal method  that, for Proxy objects, only calls the trap as a notification 
and always returns the [[GetNonConfigurablePropertyKeys]] of the target object 
(which would eventually bottom out in an ordinary object.  Because your use 
cases require sealed/frozen objects the list returned is equivalent for those 
situations to the the own property list.

I'd also eliminate all of the integrity checking from 
[Keys]]/[[GetOwnPropertyNames]] because for your use cases they simply wouldn't 
be used.  But they still have utility for people implementing pure open virtual 
objects.  Eliminating the unnecessary integrity checks greatly simplifies them 
and should make them more efficient.

Finally, because sealed/frozen is so key to  your use cases, I'd move forward 
with my suggestion for formalizing the sealed/frozen as object states.  Rather 
that something that has to be deduced from [[Extensible]] and the 
[[Configurable]]/[[Writable]] attributes. It  may not be essential 
(implementation might internally optimize it that way, anyway) but it seems 
important enough that it would be better for the spec. to be explicit about 
this rather than leaving in to implementation to figure out that such an 
optimization is important.  Also, making the state explicit eliminates all the 
individually observable [[GetOwnProperty]] calls that are otherwise needed to 
deduce frozen/sealed (and which can't be optimized away because they are 
observable via traps).  BTW, the ordering of those 

Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-21 Thread David Bruant

Le 21/11/2012 01:06, Allen Wirfs-Brock a écrit :



b) that all the elements of the result are Strings


And presumably Symbols.  We have to also accommodate Symbols, at
least for getOwnPropetyNames.  Regardless, why is this
important?  More below...


Same argument as above.

I recall there was some concern about symbols showing up in existing 
reflection methods like Object.getOwnPropertyNames. Not sure how 
that got resolved. It's basically touching upon the same issue of 
whether we can change the return type of existing methods.


I'm assuming we are excluding symbols from [[Enumerate]] and [[Keys]]

Why so? I would assume unique symbols to show up for these.


so it is only [[GetOwnPropertyNames]] that have this concern.

and of course non-enumerable unique symbols for this operation.

For both case, I think returning unique symbols work as long as ES6 
doesn't consider that objects have built-in unique-symboled properties 
(because that could probably break existing code).


One way or another we have to be able to reflectively get a list of 
symbol keyed properties.


We can either:
1) include them in the Object.getOwnPropertyNames result.

1bis) Make all built-in symbols (like @iterable) private
2) Consider getOwnPropertyNames depreciated (it actually lives 
forever) and replace it with a new Object.getOwnPropertyKeys that 
includes non-private Symbol keys
3) Keep getOwnPropertyNames as is and add Object.getOwnPropertySymbols 
that only returns the non-private-Symbol keys.


1) has the greatest backward compat concerns, but is the simplest to 
provide and for ES programmers to deal with going forward.
Since the use of Object.getOwnPropertyNames may not be widespread, maybe 
that making non-enumerable unique symbol properties could do the trick 
(as it has with new {Object, Array, etc.}.prototype additions)


1bis) If all standard built-in names are private, they're not 
enumerated, neither in for-in, Object.keys, Object.getOwnPropertyNames 
and you can have a unique name in any of these enumeration operation if 
you've added them manually, so, no backward compat (or close enough that 
it's acceptable in my opinion)
2) Eliminates the compat risk but creates perpetual potential for a: 
used gOPNames when I should have used gOPK  hazard.
3) Eliminates the compat risk but means everybody who wants to deal 
with all own properties have to deal with two lists of keys.  They 
also loose relative insertion order info relating key/symbol property 
keys.


It's a bit unfortunate to make all built-in symbols private (because 
they ought to be unique), but it feels like something acceptable.
It may induce a bit of boilerplate for proxy whitelists (because all 
built-in names like @iterable would need to be added), but a built-in 
constructor helper that would generate sets with all built-in names in 
it could solve that issue easily.


David

[1] http://wiki.ecmascript.org/doku.php?id=strawman:enumeration
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-21 Thread Andreas Rossberg
On 21 November 2012 01:06, Allen Wirfs-Brock al...@wirfs-brock.com wrote:
 Tom Van Cutsem tomvc...@gmail.com wrote:
 Allen Wirfs-Brock al...@wirfs-brock.com wrote:
 Tom Van Cutsem tomvc...@gmail.com wrote:
 c) to ensure the stability of the result.

 You can think of a + b as implementing a type coercion of the trap result
 to Array of String. This coercion is not too dissimilar from what the
 getOwnPropertyDescriptor has to do (normalization of the returned property
 descriptor by creating a fresh copy).

 Yes, premature type coercion, in my opinion. Also, a classic performance
 mistakes made by dynamic language programmers:  unnecessary coercion of
 values that are never going to be access or redundant coercion checks of
 values that are already of the property type.  Why is it important to do
 such checks on values that are are just passing through these traps.  When
 and if somebody actually gets arounds to using one of the elements that are
 returned as a property key they will be automatically coerced to a valid
 value.  Why is it important that it happens any sooner than that.

 I don't know if you are familiar with the work of Felleisen et al. on
 higher-order contracts. In that work, they use the notion of blame between
 different components/modules. Basically: if some module A receives some data
 from a module B, and B provides wrong data, then B should be assigned
 blame. You don't want to end up in a situation where A receives the blame at
 the point where it passes that wrong data into another module C.

 Yes, but ES is rampant with this sort of potentially misplaced blame.  We
 can debate whether such proper blame assignment is important or not, but I
 do believe this sort of very low level MOP interface is a situation where
 you want to absolutely minimize none essential work.  I'd sooner have it be
 a little bit more difficult to track now Proxy based bugs then to impact the
 performance of every correctly implemented proxy in every correct program.
 BTW this is a general statement about the entire proxy MOP and not just
 about these particularly property key access traps.

I'm strongly in favour of guaranteeing the contract Tom is mentioning.
However, there is an alternative to copying: we could require the
array (or array-like object) returned by the trap to be frozen. (We
could also freeze it ourselves, but that might be more problematic.)

(The fact that ES is already full of mistakes should not be an excuse
for reiterating them for new features.)

/Andreas
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-21 Thread Allen Wirfs-Brock

On Nov 21, 2012, at 1:55 AM, David Bruant wrote:

 Le 21/11/2012 01:06, Allen Wirfs-Brock a écrit :
 b) that all the elements of the result are Strings
 
 And presumably Symbols.  We have to also accommodate Symbols, at least for 
 getOwnPropetyNames.  Regardless, why is this important?  More below...
 
 Same argument as above.
 
 I recall there was some concern about symbols showing up in existing 
 reflection methods like Object.getOwnPropertyNames. Not sure how that got 
 resolved. It's basically touching upon the same issue of whether we can 
 change the return type of existing methods.
 
 I'm assuming we are excluding symbols from [[Enumerate]] and [[Keys]]
 Why so? I would assume unique symbols to show up for these.

I believe that the POR is that Symbol keys are never enumerated (even if 
associated with a the property attribute that has [[Enumerable]]: true).  I 
suppose a proxy could violate that invariant (I wouldn't want to actively 
enforce it) but would be a buggy proxy.

 
 so it is only [[GetOwnPropertyNames]] that have this concern.
 and of course non-enumerable unique symbols for this operation.

ie, private Symbols

(private Symbols, not only are always non-enumerable.  They are never reflected 
by primitive operation unless the symbol value is explicitly presented as an 
argument.  You can getOwnPropertyDescriptor using a private symbol, but 
getOwnPropertyNames never includes them)

 
 For both case, I think returning unique symbols work as long as ES6 doesn't 
 consider that objects have built-in unique-symboled properties (because that 
 could probably break existing code).

I assume by unique-symbol you mean the samething as private symbol. The above 
will hold, assuming we make @@interator, @@toStringTag, @@hasInstance, etc. 
private symbols.  While they need to be well-known, I don't see any reason why 
they shouldn't also be private.

 
 One way or another we have to be able to reflectively get a list of symbol 
 keyed properties.
 
 We can either:
 1) include them in the Object.getOwnPropertyNames result.
 1bis) Make all built-in symbols (like @iterable) private
 2) Consider getOwnPropertyNames depreciated (it actually lives forever) and 
 replace it with a new Object.getOwnPropertyKeys that includes non-private 
 Symbol keys
 3) Keep getOwnPropertyNames as is and add Object.getOwnPropertySymbols that 
 only returns the non-private-Symbol keys.
 
 1) has the greatest backward compat concerns, but is the simplest to provide 
 and for ES programmers to deal with going forward.
 Since the use of Object.getOwnPropertyNames may not be widespread, maybe that 
 making non-enumerable unique symbol properties could do the trick (as it has 
 with new {Object, Array, etc.}.prototype additions)
 
 1bis) If all standard built-in names are private, they're not enumerated, 
 neither in for-in, Object.keys, Object.getOwnPropertyNames and you can have a 
 unique name in any of these enumeration operation if you've added them 
 manually, so, no backward compat (or close enough that it's acceptable in my 
 opinion)
 2) Eliminates the compat risk but creates perpetual potential for a: used 
 gOPNames when I should have used gOPK  hazard.
 3) Eliminates the compat risk but means everybody who wants to deal with all 
 own properties have to deal with two lists of keys.  They also loose 
 relative insertion order info relating key/symbol property keys.
 
 It's a bit unfortunate to make all built-in symbols private (because they 
 ought to be unique), but it feels like something acceptable.
 It may induce a bit of boilerplate for proxy whitelists (because all built-in 
 names like @iterable would need to be added), but a built-in constructor 
 helper that would generate sets with all built-in names in it could solve 
 that issue easily.

Good point about the white lists,  that changes my mind about making the 
built-in symbols private. I think I'd prefer to take the risks of alternative  
1 rather than forcing proxy writers to deal with them in white lists.  I think 
there is probably a greater risk of people messing up whitelisting than that 
there will be campat. issues with gOPN.  Note that even in legacy code, if a 
gOPN symbol  valued element is used in any context that requires a property 
key, things will still work fine.  It is only explicitly doing string 
manipulation on a gOPN element that would cause trouble. For example, trying to 
string prefix every element a list of own property names.

My second choice would be adding getOwnPropertyKeys.  I would also only want to 
have a getOwnPropertyKeys internal method/trap and would defined 
getOwnPropertyNames as filtering that list.

Allen




 
 David
 
 [1] http://wiki.ecmascript.org/doku.php?id=strawman:enumeration

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-21 Thread Allen Wirfs-Brock

On Nov 21, 2012, at 3:54 AM, Andreas Rossberg wrote:

 On 21 November 2012 01:06, Allen Wirfs-Brock al...@wirfs-brock.com wrote:
 Tom Van Cutsem tomvc...@gmail.com wrote:
 Allen Wirfs-Brock al...@wirfs-brock.com wrote:
 Tom Van Cutsem tomvc...@gmail.com wrote:
 c) to ensure the stability of the result.
 
 You can think of a + b as implementing a type coercion of the trap result
 to Array of String. This coercion is not too dissimilar from what the
 getOwnPropertyDescriptor has to do (normalization of the returned property
 descriptor by creating a fresh copy).
 
 Yes, premature type coercion, in my opinion. Also, a classic performance
 mistakes made by dynamic language programmers:  unnecessary coercion of
 values that are never going to be access or redundant coercion checks of
 values that are already of the property type.  Why is it important to do
 such checks on values that are are just passing through these traps.  When
 and if somebody actually gets arounds to using one of the elements that are
 returned as a property key they will be automatically coerced to a valid
 value.  Why is it important that it happens any sooner than that.
 
 I don't know if you are familiar with the work of Felleisen et al. on
 higher-order contracts. In that work, they use the notion of blame between
 different components/modules. Basically: if some module A receives some data
 from a module B, and B provides wrong data, then B should be assigned
 blame. You don't want to end up in a situation where A receives the blame at
 the point where it passes that wrong data into another module C.
 
 Yes, but ES is rampant with this sort of potentially misplaced blame.  We
 can debate whether such proper blame assignment is important or not, but I
 do believe this sort of very low level MOP interface is a situation where
 you want to absolutely minimize none essential work.  I'd sooner have it be
 a little bit more difficult to track now Proxy based bugs then to impact the
 performance of every correctly implemented proxy in every correct program.
 BTW this is a general statement about the entire proxy MOP and not just
 about these particularly property key access traps.
 
 I'm strongly in favour of guaranteeing the contract Tom is mentioning.
 However, there is an alternative to copying: we could require the
 array (or array-like object) returned by the trap to be frozen. (We
 could also freeze it ourselves, but that might be more problematic.)

I'd be more favorably inclined towards freezing than I am towards copying.  
But, as you know,  ES5 does not currently produce frozen objects in these 
situations. I feel uncomfortable about enforcing a frozen invariant for traps 
where that invariant is not provided by the corresponding ordinary object 
behavior.  Perhaps I could get over that or perhaps incompatibility applying 
that requirement to ordinary objects wouldn't break anything.

Regardless, freezing and testing for frozen is, itself, not a cheap operation.  
It requires iterating over all the property descriptors of an object.  If we 
are going to build in a lot of checks of for frozen objects perhaps we should 
just make frozen (and possibly) sealed object level states rather than a 
dynamic check of all properties.  Essentially we could internally turn the 
[[Extensible]] internal property into a four state value:  
open,non-extensible,sealed,frozen.  It would make both freezing and checking 
for frozen much cheaper.

 
 (The fact that ES is already full of mistakes should not be an excuse
 for reiterating them for new features.)

I think it is usually a mistake to perform complex invariant check at low 
levels of a language engine.  Those often become performance barriers.  
Checking complex relationships belongs at higher abstraction layers.

Allen


 
 /Andreas
 

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-21 Thread Andreas Rossberg
On 21 November 2012 17:55, Allen Wirfs-Brock al...@wirfs-brock.com wrote:
 I'd be more favorably inclined towards freezing than I am towards copying.  
 But, as you know,  ES5 does not currently produce frozen objects in these 
 situations. I feel uncomfortable about enforcing a frozen invariant for traps 
 where that invariant is not provided by the corresponding ordinary object 
 behavior.  Perhaps I could get over that or perhaps incompatibility applying 
 that requirement to ordinary objects wouldn't break anything.

 Regardless, freezing and testing for frozen is, itself, not a cheap 
 operation.  It requires iterating over all the property descriptors of an 
 object.  If we are going to build in a lot of checks of for frozen objects 
 perhaps we should just make frozen (and possibly) sealed object level states 
 rather than a dynamic check of all properties.  Essentially we could 
 internally turn the [[Extensible]] internal property into a four state value: 
  open,non-extensible,sealed,frozen.  It would make both freezing and checking 
 for frozen much cheaper.

That doesn't seem necessary, because it is just as easy to optimise
the current check for the normal case where the object has been frozen
or sealed with the respective operation.

 I think it is usually a mistake to perform complex invariant check at low 
 levels of a language engine.  Those often become performance barriers.  
 Checking complex relationships belongs at higher abstraction layers.

Well, the root of the problem arguably lies with the whole idea of
proxies hooking arbitrary code into low-level operations. Perhaps
such power has to come with a cost in terms of checks and balances.
There are no higher abstraction layers in this case.

/Andreas
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-21 Thread Andreas Rossberg
On 21 November 2012 18:35, Allen Wirfs-Brock al...@wirfs-brock.com wrote:
 If you are writing any sort of generic algorithm that does a freeze check on 
 an arbitrary object you have to explicitly perform all of the internal method 
 calls because you don't know whether the object is a proxy (where every such 
 internal method call turns into an observable trap) or even some other sort 
 of exotic object implementation that can observe actual internal method 
 calls.  If there is explicit internal state is designate an object as frozen, 
 then we wouldn't have all of those potentially observable calls.

Yes, but the fast path in the VM would merely check whether you have
an ordinary object with the 'frozen' flag set. Only if that fails, or
for (most) proxies and other exotics, you have to fall back to do
something more complicated. Presumably, most practical use cases would
never hit that.

/Andreas
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-21 Thread David Bruant

Le 21/11/2012 17:37, Allen Wirfs-Brock a écrit :


On Nov 21, 2012, at 1:55 AM, David Bruant wrote:


Le 21/11/2012 01:06, Allen Wirfs-Brock a écrit :



b) that all the elements of the result are Strings


And presumably Symbols.  We have to also accommodate Symbols,
at least for getOwnPropetyNames.  Regardless, why is this
important?  More below...


Same argument as above.

I recall there was some concern about symbols showing up in 
existing reflection methods like Object.getOwnPropertyNames. Not 
sure how that got resolved. It's basically touching upon the same 
issue of whether we can change the return type of existing methods.


I'm assuming we are excluding symbols from [[Enumerate]] and [[Keys]]

Why so? I would assume unique symbols to show up for these.


I believe that the POR is that Symbol keys are never enumerated (even 
if associated with a the property attribute that has [[Enumerable]]: 
true).  I suppose a proxy could violate that invariant (I wouldn't 
want to actively enforce it) but would be a buggy proxy.

What does POR mean?






so it is only [[GetOwnPropertyNames]] that have this concern.

and of course non-enumerable unique symbols for this operation.


ie, private Symbols

(private Symbols, not only are always non-enumerable.  They are never 
reflected by primitive operation unless the symbol value is explicitly 
presented as an argument.  You can getOwnPropertyDescriptor using a 
private symbol, but getOwnPropertyNames never includes them)


For both case, I think returning unique symbols work as long as ES6 
doesn't consider that objects have built-in unique-symboled 
properties (because that could probably break existing code).


I assume by unique-symbol you mean the samething as private symbol.

Indeed, I meant private here, sorry for the mistake.

The above will hold, assuming we make @@interator, @@toStringTag, 
@@hasInstance, etc. private symbols.  While they need to be 
well-known, I don't see any reason why they shouldn't also be private.

+1

Good point about the white lists,  that changes my mind about making 
the built-in symbols private. I think I'd prefer to take the risks of 
alternative  1 rather than forcing proxy writers to deal with them in 
white lists.  I think there is probably a greater risk of people 
messing up whitelisting than that there will be campat. issues with gOPN.
If the proxy module provides a constructor like 
BuiltInPrivateNamesWeakSet, things could be fine:


var whitelist = new BuiltInPrivateNamesWeakSet();
whitelist.add(...) // adding user generated private names if applicable
var p = new Proxy(target, handler, whitelist);

The name I'm proposing is a bit long, but that would solve the built-in 
private name micro management problem elegantly enough as far as I'm 
concerned. It's also future-proof in the sense that if new built-in 
private names are added, the weakset will do the right thing in updated 
environments.
If people want to build the weakset manually, they would be free to do 
so, but at least, the helper would do the annoying part on behalf of the 
user.
We can consider that if the third argument is omitted, all built-in 
private names pass. That sounds like a good useful default.


David
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-21 Thread Tom Van Cutsem

 2012/11/19 Allen Wirfs-Brock al...@wirfs-brock.com

 On Nov 19, 2012, at 10:04 AM, Tom Van Cutsem wrote:


 It's all a matter of developer expectations and how much leeway we have in
 changing the return type of existing built-ins.
 In theory, it's a backwards-incompatible change. In practice, it may not
 matter.


 It can't break existing code that doesn't use Proxies.


It's very likely that existing ES5 code (which doesn't use or know about
proxies) will come to interact with ES6 proxies. Consider a sandboxed JS
environment that provides a wrapped DOM (implemented using proxies). The
ES5 code loaded into the sandbox doesn't actively use proxies; it will
interact with proxies unknowingly. That's the kind of scenarios for which
we should be careful with backwards-incompatible changes.



 b) that all the elements of the result are Strings


 And presumably Symbols.  We have to also accommodate Symbols, at least
 for getOwnPropetyNames.  Regardless, why is this important?  More below...


 Same argument as above.

 I recall there was some concern about symbols showing up in existing
 reflection methods like Object.getOwnPropertyNames. Not sure how that got
 resolved. It's basically touching upon the same issue of whether we can
 change the return type of existing methods.


 I'm assuming we are excluding symbols from [[Enumerate]] and [[Keys]] so
 it is only [[GetOwnPropertyNames]] that have this concern.

 One way or another we have to be able to reflectively get a list of symbol
 keyed properties.

 We can either:
 1) include them in the Object.getOwnPropertyNames result.
 2) Consider getOwnPropertyNames depreciated (it actually lives forever)
 and replace it with a new Object.getOwnPropertyKeys that includes
 non-private Symbol keys
 3) Keep getOwnPropertyNames as is and add Object.getOwnPropertySymbols
 that only returns the non-private-Symbol keys.

 1) has the greatest backward compat concerns, but is the simplest to
 provide and for ES programmers to deal with going forward.
 2) Eliminates the compat risk but creates perpetual potential for a: used
 gOPNames when I should have used gOPK  hazard.
 3) Eliminates the compat risk but means everybody who wants to deal with
 all own properties have to deal with two lists of keys.  They also loose
 relative insertion order info relating key/symbol property keys.

 Either 2 or 3 could require widening the MOP which increases the
 possibility for incomplete, inconsistent, or otherwise buggy proxies.  Even
 if we expose multiple public functions like either 2 or 3 I would still
 prefer to only have a single getOwnProperyyKeys internal method/trap that
 can be filtered to provide just strings and/or symbols.  Overall, I'm more
 concerned about keeping the internal method/trap MOP width as narrow as
 possible than I am about the size of the public Object.* API


Let's first discuss whether there is an issue with just letting (unique)
symbols show up in Object.{keys,getOwnPropertyNames}.
It's still a change in return type (from Array[String] to
Array[String|Symbol]), but a far less innocuous one than changing
Array[String] into Any.




 c) to ensure the stability of the result.

 You can think of a + b as implementing a type coercion of the trap result
 to Array of String. This coercion is not too dissimilar from what the
 getOwnPropertyDescriptor has to do (normalization of the returned property
 descriptor by creating a fresh copy).


 Yes, premature type coercion, in my opinion. Also, a classic performance
 mistakes made by dynamic language programmers:  unnecessary coercion of
 values that are never going to be access or redundant coercion checks of
 values that are already of the property type.  Why is it important to do
 such checks on values that are are just passing through these traps.  When
 and if somebody actually gets arounds to using one of the elements that are
 returned as a property key they will be automatically coerced to a valid
 value.  Why is it important that it happens any sooner than that.


 I don't know if you are familiar with the work of Felleisen et al. on
 higher-order contracts. In that work, they use the notion of blame
 between different components/modules. Basically: if some module A receives
 some data from a module B, and B provides wrong data, then B should be
 assigned blame. You don't want to end up in a situation where A receives
 the blame at the point where it passes that wrong data into another
 module C.


 Yes, but ES is rampant with this sort of potentially misplaced blame.  We
 can debate whether such proper blame assignment is important or not, but
 I do believe this sort of very low level MOP interface is a situation where
 you want to absolutely minimize none essential work.  I'd sooner have it be
 a little bit more difficult to track now Proxy based bugs then to impact
 the performance of every correctly implemented proxy in every correct
 program. BTW this is a general statement about the entire proxy MOP 

Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-21 Thread Tom Van Cutsem
2012/11/21 David Bruant bruan...@gmail.com

  Since the use of Object.getOwnPropertyNames may not be widespread, maybe
 that making non-enumerable unique symbol properties could do the trick (as
 it has with new {Object, Array, etc.}.prototype additions)

 1bis) If all standard built-in names are private, they're not enumerated,
 neither in for-in, Object.keys, Object.getOwnPropertyNames and you can have
 a unique name in any of these enumeration operation if you've added them
 manually, so, no backward compat (or close enough that it's acceptable in
 my opinion)


Even disregarding the proxy whitelist hassle, let's not go there. Making
all the well-known unique symbols, like @iterator, private just so they
don't appear in Object.getOwnPropertyNames feels silly to me. We have the
distinction between unique and private symbols precisely because we've
identified a need for symbols that need to be unique but not necessarily
private!

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-21 Thread Tom Van Cutsem
2012/11/21 Allen Wirfs-Brock al...@wirfs-brock.com

 I'd be more favorably inclined towards freezing than I am towards copying.
  But, as you know,  ES5 does not currently produce frozen objects in these
 situations. I feel uncomfortable about enforcing a frozen invariant for
 traps where that invariant is not provided by the corresponding ordinary
 object behavior.  Perhaps I could get over that or perhaps incompatibility
 applying that requirement to ordinary objects wouldn't break anything.


While the arrays produced by Object.keys etc. aren't frozen, there's an
implicit guarantee that those arrays will not further be modified
implicitly by any other operation in the program. Of course a program can
choose to explicitly mutate it. But there's no magical action-at-a-distance.

Currently, we provide the same guarantee in the face of proxies by
defensively copying the trap result into a fresh array. Requiring the
trap result to be frozen feels OK to me, except that it doesn't play well
with the current default of automatically forwarding:

var p = Proxy(target, { })
Object.keys(p) // error: keys trap did not return a frozen array

var p = Proxy(target, { keys: function(t) { return
Object.freeze(Object.keys(t)); })
Object.keys(p) // now it works

One way to get rid of this irregularity is indeed to make Object.keys
always return frozen arrays. I don't think it would hurt performance, as
implementations already aren't allowed to reuse arrays returned from
Object.keys (of course they can always cheat as long as they don't get
caught).


 Regardless, freezing and testing for frozen is, itself, not a cheap
 operation.  It requires iterating over all the property descriptors of an
 object.  If we are going to build in a lot of checks of for frozen objects
 perhaps we should just make frozen (and possibly) sealed object level
 states rather than a dynamic check of all properties.  Essentially we could
 internally turn the [[Extensible]] internal property into a four state
 value:  open,non-extensible,sealed,frozen.  It would make both freezing and
 checking for frozen much cheaper.


As Andreas mentioned, for normal objects, isFrozen checks can be optimized
to O(1).
For proxies, if we leave in the derived isFrozen trap, the check could also
be O(1).

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-21 Thread Tom Van Cutsem
2012/11/21 Mark S. Miller erig...@google.com

 On Wed, Nov 21, 2012 at 8:55 AM, Allen Wirfs-Brock
 al...@wirfs-brock.com wrote:
  [...] Essentially we could internally turn the [[Extensible]] internal
 property into a four state value:  open,non-extensible,sealed,frozen.  [...]

 First, my apologies for not yet finding the time to catch up on this
 thread. But I did want to encourage this particular idea. We may not
 be able to make this work out, but it would have many benefits if we
 could. For example, the isFrozen check in the Object.observe API
 would make more sense if this were a simple state rather than a
 pattern check. More later...


A lot of the complexity of the current invariant checks derives from the
fact that Javascript objects have (too) fine-grained invariants (i.e.
non-configurability at the level of individual properties,
non-extensibility at the level of the object, and all possible combinations
in between). This means we have to account for weird cases such as a
non-extensible object with all but 1 property being non-configurable (an
almost-frozen object).

If JS objects could be in only one of four states, things would be a lot
simpler to reason about. That said, I don't see how we can get there
without radically breaking with ES5's view of object invariants.

Cheers,
Tom
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-21 Thread Allen Wirfs-Brock

On Nov 21, 2012, at 11:13 AM, David Bruant wrote:

 Le 21/11/2012 17:37, Allen Wirfs-Brock a écrit :
 
 On Nov 21, 2012, at 1:55 AM, David Bruant wrote:
 
 Le 21/11/2012 01:06, Allen Wirfs-Brock a écrit :
 b) that all the elements of the result are Strings
 
 And presumably Symbols.  We have to also accommodate Symbols, at least 
 for getOwnPropetyNames.  Regardless, why is this important?  More 
 below...
 
 Same argument as above.
 
 I recall there was some concern about symbols showing up in existing 
 reflection methods like Object.getOwnPropertyNames. Not sure how that 
 got resolved. It's basically touching upon the same issue of whether we 
 can change the return type of existing methods.
 
 I'm assuming we are excluding symbols from [[Enumerate]] and [[Keys]]
 Why so? I would assume unique symbols to show up for these.
 
 I believe that the POR is that Symbol keys are never enumerated (even if 
 associated with a the property attribute that has [[Enumerable]]: true).  I 
 suppose a proxy could violate that invariant (I wouldn't want to actively 
 enforce it) but would be a buggy proxy.
 What does POR mean?
 

Plan of Record

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-21 Thread Kevin Reid
On Wed, Nov 21, 2012 at 12:42 PM, Tom Van Cutsem tomvc...@gmail.com wrote:

 2012/11/21 Mark S. Miller erig...@google.com

 On Wed, Nov 21, 2012 at 8:55 AM, Allen Wirfs-Brock
 al...@wirfs-brock.com wrote:
  [...] Essentially we could internally turn the [[Extensible]] internal
 property into a four state value:  open,non-extensible,sealed,frozen.  [...]

 [...]
 If JS objects could be in only one of four states, things would be a lot
 simpler to reason about. That said, I don't see how we can get there
 without radically breaking with ES5's view of object invariants.


Why can't an implementation cache the knowledge that an object is frozen
(after Object.freeze or after a full pattern-check) exactly as if the
fourth state exists, and get the efficiency benefit (but not the
observability-of-the-test-on-a-proxy benefit) without changing the ES5
model?
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-21 Thread David Bruant

Le 21/11/2012 21:13, Tom Van Cutsem a écrit :

2012/11/21 David Bruant bruan...@gmail.com mailto:bruan...@gmail.com

Since the use of Object.getOwnPropertyNames may not be widespread,
maybe that making non-enumerable unique symbol properties could do
the trick (as it has with new {Object, Array, etc.}.prototype
additions)

1bis) If all standard built-in names are private, they're not
enumerated, neither in for-in, Object.keys,
Object.getOwnPropertyNames and you can have a unique name in any
of these enumeration operation if you've added them manually, so,
no backward compat (or close enough that it's acceptable in my
opinion)


Even disregarding the proxy whitelist hassle, let's not go there. 
Making all the well-known unique symbols, like @iterator, private just 
so they don't appear in Object.getOwnPropertyNames feels silly to me. 
We have the distinction between unique and private symbols precisely 
because we've identified a need for symbols that need to be unique but 
not necessarily private!
Rest assured that it doesn't make me happy to propose this idea, but it 
seems worthwhile to explore.


Allen's latest point about backward compat makes me feel that it may not 
be that big of a problem (Note that even in legacy code, if a gOPN 
symbol  valued element is used in any context that requires a property 
key, things will still work fine.  It is only explicitly doing string 
manipulation on a gOPN element that would cause trouble. For example, 
trying to string prefix every element a list of own property names.)

I guess only user testing could tell.
If absolutely necessary, it may not be absurd to have the following: 
string + unique name = new unique name.


David
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-21 Thread Allen Wirfs-Brock

On Nov 21, 2012, at 12:09 PM, Tom Van Cutsem wrote:

 2012/11/19 Allen Wirfs-Brock al...@wirfs-brock.com
 On Nov 19, 2012, at 10:04 AM, Tom Van Cutsem wrote:
 
 It's all a matter of developer expectations and how much leeway we have in 
 changing the return type of existing built-ins.
 In theory, it's a backwards-incompatible change. In practice, it may not 
 matter.
 
 It can't break existing code that doesn't use Proxies.
 
 It's very likely that existing ES5 code (which doesn't use or know about 
 proxies) will come to interact with ES6 proxies. Consider a sandboxed JS 
 environment that provides a wrapped DOM (implemented using proxies). The ES5 
 code loaded into the sandbox doesn't actively use proxies; it will interact 
 with proxies unknowingly. That's the kind of scenarios for which we should be 
 careful with backwards-incompatible changes.

Presumably in this scenario it is the sandbox that is providing the Proxy so it 
can make to always return a built-in array if it is concerned about this.

The trade-off is always doing an extra copy of an object, just because of the 
unlikely possibility that a trap implementor doesn't use an actual built-in 
array.  

On the other hand, it seems very unlikely that realistic consumers of the 
existing Object.keys/Object.getOwnPropertyNames are actually doing an 
Array.isArray checks on the value produced from them. What would be the point?

  
 
 b) that all the elements of the result are Strings
 
 And presumably Symbols.  We have to also accommodate Symbols, at least for 
 getOwnPropetyNames.  Regardless, why is this important?  More below...
 
 Same argument as above.
 
 I recall there was some concern about symbols showing up in existing 
 reflection methods like Object.getOwnPropertyNames. Not sure how that got 
 resolved. It's basically touching upon the same issue of whether we can 
 change the return type of existing methods.
 
 I'm assuming we are excluding symbols from [[Enumerate]] and [[Keys]] so it 
 is only [[GetOwnPropertyNames]] that have this concern.
 
 One way or another we have to be able to reflectively get a list of symbol 
 keyed properties.
 
 We can either:
 1) include them in the Object.getOwnPropertyNames result.
 2) Consider getOwnPropertyNames depreciated (it actually lives forever) and 
 replace it with a new Object.getOwnPropertyKeys that includes non-private 
 Symbol keys
 3) Keep getOwnPropertyNames as is and add Object.getOwnPropertySymbols that 
 only returns the non-private-Symbol keys.
 
 1) has the greatest backward compat concerns, but is the simplest to provide 
 and for ES programmers to deal with going forward.
 2) Eliminates the compat risk but creates perpetual potential for a: used 
 gOPNames when I should have used gOPK  hazard.
 3) Eliminates the compat risk but means everybody who wants to deal with all 
 own properties have to deal with two lists of keys.  They also loose relative 
 insertion order info relating key/symbol property keys.
 
 Either 2 or 3 could require widening the MOP which increases the possibility 
 for incomplete, inconsistent, or otherwise buggy proxies.  Even if we expose 
 multiple public functions like either 2 or 3 I would still prefer to only 
 have a single getOwnProperyyKeys internal method/trap that can be filtered to 
 provide just strings and/or symbols.  Overall, I'm more concerned about 
 keeping the internal method/trap MOP width as narrow as possible than I am 
 about the size of the public Object.* API
 
 Let's first discuss whether there is an issue with just letting (unique) 
 symbols show up in Object.{keys,getOwnPropertyNames}.
 It's still a change in return type (from Array[String] to 
 Array[String|Symbol]), but a far less innocuous one than changing 
 Array[String] into Any.

Wow, I actually think that the Array[String|Symbol] change is far more likely 
to have actual compatibility impact.  I can imagine various scenarios where is 
program or library is doing string processing on the elements returned from 
keys/getOPN.  That seems far more likely, then that they have dependencies upon 
the returned collection being Array.isArray rather than just Array-like.

 
  
 
 c) to ensure the stability of the result.
 
 You can think of a + b as implementing a type coercion of the trap result 
 to Array of String. This coercion is not too dissimilar from what the 
 getOwnPropertyDescriptor has to do (normalization of the returned property 
 descriptor by creating a fresh copy).
 
 Yes, premature type coercion, in my opinion. Also, a classic performance 
 mistakes made by dynamic language programmers:  unnecessary coercion of 
 values that are never going to be access or redundant coercion checks of 
 values that are already of the property type.  Why is it important to do 
 such checks on values that are are just passing through these traps.  When 
 and if somebody actually gets arounds to using one of the elements that are 
 returned as a property key they will be 

Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-21 Thread Allen Wirfs-Brock

On Nov 21, 2012, at 12:27 PM, Tom Van Cutsem wrote:

 2012/11/21 Allen Wirfs-Brock al...@wirfs-brock.com
 I'd be more favorably inclined towards freezing than I am towards copying.  
 But, as you know,  ES5 does not currently produce frozen objects in these 
 situations. I feel uncomfortable about enforcing a frozen invariant for traps 
 where that invariant is not provided by the corresponding ordinary object 
 behavior.  Perhaps I could get over that or perhaps incompatibility applying 
 that requirement to ordinary objects wouldn't break anything.
 
 While the arrays produced by Object.keys etc. aren't frozen, there's an 
 implicit guarantee that those arrays will not further be modified implicitly 
 by any other operation in the program. Of course a program can choose to 
 explicitly mutate it. But there's no magical action-at-a-distance.
 
 Currently, we provide the same guarantee in the face of proxies by 
 defensively copying the trap result into a fresh array. Requiring the trap 
 result to be frozen feels OK to me, except that it doesn't play well with the 
 current default of automatically forwarding:
 
 var p = Proxy(target, { })
 Object.keys(p) // error: keys trap did not return a frozen array
 
 var p = Proxy(target, { keys: function(t) { return 
 Object.freeze(Object.keys(t)); })
 Object.keys(p) // now it works


Wait, Object.keys as now just implemented by calling the [[Keys]] internal 
method and it doesn't have any idea about what kind of object that internal 
method is being called upon.
So it must apply the same rules to both the result of ordinary object [[Keys]] 
and proxy [[Keys]].  Object.keys could always copy the result or always freeze 
its result or accept either frozen/non-frozen but all [[Keys]] invocation need 
to be treated equally. 

 
 One way to get rid of this irregularity is indeed to make Object.keys always 
 return frozen arrays. I don't think it would hurt performance, as 
 implementations already aren't allowed to reuse arrays returned from 
 Object.keys (of course they can always cheat as long as they don't get 
 caught).

But client of Object.keys are currently permitted to modify its result array.  
Freezing it would break such clients.
  
 Regardless, freezing and testing for frozen is, itself, not a cheap 
 operation.  It requires iterating over all the property descriptors of an 
 object.  If we are going to build in a lot of checks of for frozen objects 
 perhaps we should just make frozen (and possibly) sealed object level states 
 rather than a dynamic check of all properties.  Essentially we could 
 internally turn the [[Extensible]] internal property into a four state value: 
  open,non-extensible,sealed,frozen.  It would make both freezing and checking 
 for frozen much cheaper.
 
 As Andreas mentioned, for normal objects, isFrozen checks can be optimized to 
 O(1).
 For proxies, if we leave in the derived isFrozen trap, the check could also 
 be O(1).

Are you sure about that last point?  What if the target is a Proxy or some 
other exotic object that is observing internal method calls on itself.  This is 
one of my overall concerns about some of the more complex invariant checking 
algorithms.  Our interoperability rules require strict ordering of all 
observable operations and internal method/trap calls are potentially 
observable. 

Allen


___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-21 Thread Allen Wirfs-Brock

On Nov 21, 2012, at 12:42 PM, Tom Van Cutsem wrote:

 2012/11/21 Mark S. Miller erig...@google.com
 On Wed, Nov 21, 2012 at 8:55 AM, Allen Wirfs-Brock
 al...@wirfs-brock.com wrote:
  [...] Essentially we could internally turn the [[Extensible]] internal 
  property into a four state value:  open,non-extensible,sealed,frozen.  [...]
 
 First, my apologies for not yet finding the time to catch up on this
 thread. But I did want to encourage this particular idea. We may not
 be able to make this work out, but it would have many benefits if we
 could. For example, the isFrozen check in the Object.observe API
 would make more sense if this were a simple state rather than a
 pattern check. More later...
 
 A lot of the complexity of the current invariant checks derives from the fact 
 that Javascript objects have (too) fine-grained invariants (i.e. 
 non-configurability at the level of individual properties, non-extensibility 
 at the level of the object, and all possible combinations in between). This 
 means we have to account for weird cases such as a non-extensible object with 
 all but 1 property being non-configurable (an almost-frozen object).
 
 If JS objects could be in only one of four states, things would be a lot 
 simpler to reason about. That said, I don't see how we can get there without 
 radically breaking with ES5's view of object invariants.

Of course, I don't necessarily agree that ES5 has such a view of object 
invariants... ;-)

However, everything we currently have in ES5 maps to one of those fours states. 
 Do you actually care very much, form a reasoning perspective,  about a open 
object with some non-configurable properties.  Or an non-extensible object with 
with some configurable properties?  

Overall, I think having the four states makes the conceptual model clearer and 
might guide us in cleaning up the MOP.

Allen








 
 Cheers,
 Tom

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Fwd: possible excessive proxy invariants for Object.keys/etc??

2012-11-20 Thread Allen Wirfs-Brock
Tom Van Custem have been having some email discussion while I work on 
integrating Proxys into the ES6 spec.  He and I agree that some broader input 
would be useful so I'm going to forward some of the message here to es-discuss 
and carry the discussion forward here.  Here is the first message with other to 
follow:

Begin forwarded message:

 From: Allen Wirfs-Brock al...@wirfs-brock.com
 Date: November 18, 2012 1:26:14 PM PST
 To: Tom Van Cutsem tomvc...@gmail.com, Mark S. Miller erig...@google.com
 Cc: Jason Orendorff jorendo...@mozilla.com
 Subject: possible excessive proxy invariants for Object.keys/etc??
 
 I'm wondering if the wiki spec. for these functions aren't doing invariant 
 checking that goes beyond what is required for the integrity purposes you 
 have stated.
 
 In general, proxies  traps check to ensure that the invariants of a 
 sealed/frozen target object aren't violated.  Generally, only minimal 
 processing needs to be done if the target is extensible and has no 
 non-configurable properties.  In fact the Virtual Object proposal says As 
 long as the proxy does not expose non-configurable properties or becomes 
 non-extensible, the target object is fully ignored (except to acquire 
 internal properties such as [[Class]]). . 
 
 The proxy spec.for Object.getOwnPropertyNames/kets/etc. seem to be doing 
 quite a bit more than this.  They
 
 1) always copy the array returned from the trap?  Why is this necessary?  
 Sure the author of a trap should probably always return a fresh object but 
 not doing so doesn't violate the integrity of the frozen/sealed invariants?  
 In most cases they will provide a fresh object and  copying adds unnecessary  
 work  that is proportional to the number of names to every such call.
 
 2) ensuring that the list of property keys contains no duplicates.  Why is 
 this essential?  Again, I don't see what it has to do with the integrity of 
 the frozen/sealed invariants.  It is extra and probably unnecessary work that 
 is at least proportional to the number of names).
 
 3) Every name in the list returned by the trap code is looked up on the 
 target to determine whether or not it exists, even if the target is 
 extensible.   Each of those lookup is observable (the target might itself be 
 a proxy) so, according to the algorithm they all must be performed.
 
 4) Every own property of the target, is observably looked up (possibly a 
 second time) even if the object is extensible  and has no non-configurable 
 properties.
 
 
 It isn't clear to me if any of this work is really necessary to ensure 
 integrity.  After all, what can you do with any of these names other than use 
 them as the property key argument to some other trap/internal method such as 
 [[SetP]], [[DefineOwnProperty]], etc.  Called on a proxy, those fundamental 
 operations are going to enforce the integrity invariants of the actual 
 properties involved so the get name checks doesn't really seem to be adding 
 anything essential.
 
 Perhaps we can just get rid of all the above checking.  It seems like a good 
 idea to me.
 
 Alternatively,  it suggests that a [[GetNonConfigurablePropertyNames]] 
 internal method/trap would be a useful call to have as the integrity 
 invariants only care about non-configurable properties. That would 
 significantly limit the work in the case where there are none and limit the 
 observable trap calls to only the non-configurable properties.
 
 Allen

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-20 Thread Tom Van Cutsem
Hi Allen,

2012/11/18 Allen Wirfs-Brock al...@wirfs-brock.com
The proxy spec.for Object.getOwnPropertyNames/kets/etc. seem to be doing quite 
a bit more than this. They

1) always copy the array returned from the trap?  Why is this necessary?  Sure 
the author of a trap should probably always return a fresh object but not doing 
so doesn't violate the integrity of the frozen/sealed invariants?  In most 
cases they will provide a fresh object and  copying adds unnecessary  work  
that is proportional to the number of names to every such call.

The copying is to ensure:
a) that the result is an Array
b) that all the elements of the result are Strings
c) to ensure the stability of the result.

You can think of a + b as implementing a type coercion of the trap result to 
Array of String. This coercion is not too dissimilar from what the 
getOwnPropertyDescriptor has to do (normalization of the returned property 
descriptor by creating a fresh copy).

c) on the other hand is crucial for the non-configurability/non-extensibility 
checks mentioned below. It's no use checking some invariants on a data 
structure if that data structure can later still be mutated.

If we don't care about any of a, b and c, then the result array wouldn't need 
to be copied.
 
2) ensuring that the list of property keys contains no duplicates.  Why is this 
essential?  Again, I don't see what it has to do with the integrity of the 
frozen/sealed invariants.  It is extra and probably unnecessary work that is at 
least proportional to the number of names).

We've been going back and forth over whether or not we wanted to prevent 
duplicates. I remember Andreas Gal being concerned about these kinds of issues 
(that was when he was doing the first Firefox prototype for old proxies, in the 
context of the enumerate() trap, which was called during a live for-in loop. 
IIRC, Firefox already did de-dupe checks, as properties already enumerated in a 
child object should not be re-visited when visiting a parent object)

More recently, at the last TC39 meeting in Boston, we decided to change the 
return type of the enumerate() trap from Array[String] to Iterator, and in 
doing so waiving the duplicate properties check. Quoting from the Open issues 
section of 
http://wiki.ecmascript.org/doku.php?id=harmony:direct_proxies#open_issues:

Enumerate trap signature: consider making the enumerate() trap return an 
iterator rather than an array of strings. To retain the benefits of an iterator 
(no need to store collection in memory), we might need to waive the duplicate 
properties check. Resolution: accepted (duplicate properties check is waived in 
favor of iterator return type)

I guess if duplicate properties are not crucial for enumeration, they're also 
not crucial for Object.getOwnPropertyNames and Object.keys and can be dropped. 
Mark, can you comment?
 
3) Every name in the list returned by the trap code is looked up on the target 
to determine whether or not it exists, even if the target is extensible.   Each 
of those lookup is observable (the target might itself be a proxy) so, 
according to the algorithm they all must be performed.

This is where we get into actual checks required to enforce 
non-configurability/non-extensibility.

Granted, the ES5 spec is not clear about the invariants on getOwnPropertyNames 
and keys. The currently specified invariants are a common-sense extrapolation 
of the existing invariants to cover these operations.

In practice, it determines the degree of confidence that a programmer can have 
in Object.getOwnPropertyNames and friends when dealing with a frozen object. If 
we waive these invariant checks, then the result of those operations can never 
be trusted on to reliably introspect on a frozen object's list of property 
names:

Object.isFrozen(proxy) // true
Object.getOwnPropertyNames(proxy) // ['foo']
Object.getOwnPropertyNames(proxy) // [ ]

Here, the 'foo' property apparently disappeared on a frozen object.

If neither the for-in loop nor Object.getOwnPropertyNames nor Object.keys can 
reliably report an object's own properties, then we've made it impossible to 
reliably traverse and inspect a presumably deep-frozen object graph.
 
4) Every own property of the target, is observably looked up (possibly a second 
time) even if the object is extensible  and has no non-configurable properties.

We may be able to remove the redundancy of two lookups by restructuring the 
algorithm.
There previously was some redundancy in other checks as well.
 
It isn't clear to me if any of this work is really necessary to ensure 
integrity.  After all, what can you do with any of these names other than use 
them as the property key argument to some other trap/internal method such as 
[[SetP]], [[DefineOwnProperty]], etc.  Called on a proxy, those fundamental 
operations are going to enforce the integrity invariants of the actual 
properties involved so the get name checks doesn't really seem to be adding 
anything 

Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-20 Thread Allen Wirfs-Brock

On Nov 19, 2012, at 10:04 AM, Tom Van Cutsem wrote:

 Hi Allen,
 
 2012/11/18 Allen Wirfs-Brock al...@wirfs-brock.com
 The proxy spec.for Object.getOwnPropertyNames/kets/etc. seem to be doing 
 quite a bit more than this. They
 
 1) always copy the array returned from the trap?  Why is this necessary?  
 Sure the author of a trap should probably always return a fresh object but 
 not doing so doesn't violate the integrity of the frozen/sealed invariants?  
 In most cases they will provide a fresh object and  copying adds unnecessary  
 work  that is proportional to the number of names to every such call.
 
 The copying is to ensure:
 a) that the result is an Array

Why is Array-ness essential?  It was what ES5 specified, but ES5 had a fixed 
implementations of Object.getOwnPropertyNames/keys so that requirement was 
simply a reflection of what the  spec's algorithms actually did.  Most places 
in the specification that consume an array only require array-like-ness, not 
an actual array.  Now that we're make the implementation of the getOPN/keys 
extensible, it would be natural to relax the requirement that they produce a  
[[Class]]===Array object.

 b) that all the elements of the result are Strings

And presumably Symbols.  We have to also accommodate Symbols, at least for 
getOwnPropetyNames.  Regardless, why is this important?  More below...

 c) to ensure the stability of the result.
 
 You can think of a + b as implementing a type coercion of the trap result to 
 Array of String. This coercion is not too dissimilar from what the 
 getOwnPropertyDescriptor has to do (normalization of the returned property 
 descriptor by creating a fresh copy).

Yes, premature type coercion, in my opinion. Also, a classic performance 
mistakes made by dynamic language programmers:  unnecessary coercion of values 
that are never going to be access or redundant coercion checks of values that 
are already of the property type.  Why is it important to do such checks on 
values that are are just passing through these traps.  When and if somebody 
actually gets arounds to using one of the elements that are returned as a 
property key they will be automatically coerced to a valid value.  Why is it 
important that it happens any sooner than that.

getOwnPropertyDescriptor is also on my list to talk to you about for similar 
reasons.  I don't see why the property descriptor needs to be normalized and 
regenerated (including converting accessor properties on the descriptor into 
data properties and requiring the [[Prototype]] to be object.  I have an 
alternative for [[GetOwnProperty]]/TrapGetOwnPropertyDescriptor that preserves 
the original object returned from the trap (while normalizing to a descriptor 
record for any internal calls on ordinary objects).  This preserves any exotic 
property descriptor object properties as is.  This seems like exactly the right 
things.  Such exotic property descriptor properties can only be meaningfully 
used by other proxy traps or application/library code that knows about them.  I 
don't see any need to normalize them into data properties or otherwise muck 
with what the actually implementor of the getOwnPropertyDescrptor trap choose 
to return. 

I this alternative implementation is, again, much simpler (and efficient) with 
fewer externally observable calls in its algorithm steps.  I sure you will want 
to review it so I will include it in the spec. draft.

 
 c) on the other hand is crucial for the non-configurability/non-extensibility 
 checks mentioned below. It's no use checking some invariants on a data 
 structure if that data structure can later still be mutated.
I don't see how an extra copy of the the result array makes any difference in 
this regard  (also see below).   The array returned from 
Object.getOwnPropertyNames is still mutable even after you make a copy. It's 
only as stable as any other non-frozen object you are likely to encounter. 


 
 If we don't care about any of a, b and c, then the result array wouldn't need 
 to be copied.
yes, I believe that should be the case.

  
 2) ensuring that the list of property keys contains no duplicates.  Why is 
 this essential?  Again, I don't see what it has to do with the integrity of 
 the frozen/sealed invariants.  It is extra and probably unnecessary work that 
 is at least proportional to the number of names).
 
 We've been going back and forth over whether or not we wanted to prevent 
 duplicates. I remember Andreas Gal being concerned about these kinds of 
 issues (that was when he was doing the first Firefox prototype for old 
 proxies, in the context of the enumerate() trap, which was called during a 
 live for-in loop. IIRC, Firefox already did de-dupe checks, as properties 
 already enumerated in a child object should not be re-visited when visiting a 
 parent object)
 
 More recently, at the last TC39 meeting in Boston, we decided to change the 
 return type of the enumerate() trap from Array[String] to 

Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-20 Thread Tom Van Cutsem
2012/11/19 Allen Wirfs-Brock al...@wirfs-brock.com
On Nov 19, 2012, at 10:04 AM, Tom Van Cutsem wrote:
 The copying is to ensure:
 a) that the result is an Array

Why is Array-ness essential?  It was what ES5 specified, but ES5 had a fixed 
implementations of Object.getOwnPropertyNames/keys so that requirement was 
simply a reflection of what the  spec's algorithms actually did.  Most places 
in the specification that consume an array only require array-like-ness, not 
an actual array.  Now that we're make the implementation of the getOPN/keys 
extensible, it would be natural to relax the requirement that they produce a  
[[Class]]===Array object.

It's all a matter of developer expectations and how much leeway we have in 
changing the return type of existing built-ins.
In theory, it's a backwards-incompatible change. In practice, it may not matter.
 b) that all the elements of the result are Strings

And presumably Symbols.  We have to also accommodate Symbols, at least for 
getOwnPropetyNames.  Regardless, why is this important?  More below...

Same argument as above.

I recall there was some concern about symbols showing up in existing reflection 
methods like Object.getOwnPropertyNames. Not sure how that got resolved. It's 
basically touching upon the same issue of whether we can change the return type 
of existing methods.
 

 c) to ensure the stability of the result.
 
 You can think of a + b as implementing a type coercion of the trap result to 
 Array of String. This coercion is not too dissimilar from what the 
 getOwnPropertyDescriptor has to do (normalization of the returned property 
 descriptor by creating a fresh copy).

Yes, premature type coercion, in my opinion. Also, a classic performance 
mistakes made by dynamic language programmers:  unnecessary coercion of values 
that are never going to be access or redundant coercion checks of values that 
are already of the property type.  Why is it important to do such checks on 
values that are are just passing through these traps.  When and if somebody 
actually gets arounds to using one of the elements that are returned as a 
property key they will be automatically coerced to a valid value.  Why is it 
important that it happens any sooner than that.

I don't know if you are familiar with the work of Felleisen et al. on 
higher-order contracts. In that work, they use the notion of blame between 
different components/modules. Basically: if some module A receives some data 
from a module B, and B provides wrong data, then B should be assigned blame. 
You don't want to end up in a situation where A receives the blame at the point 
where it passes that wrong data into another module C.

The early type coercions at the exit of the traps can be thought of in these 
terms: the invariant checks will always blame the proxy handler for producing 
wrong data, at the point where the wrong data is produced and before it's 
exposed to client code. Clients are expecting ES5/6 objects to obey an implicit 
contract.
 
getOwnPropertyDescriptor is also on my list to talk to you about for similar 
reasons.  I don't see why the property descriptor needs to be normalized and 
regenerated (including converting accessor properties on the descriptor into 
data properties and requiring the [[Prototype]] to be object.  I have an 
alternative for [[GetOwnProperty]]/TrapGetOwnPropertyDescriptor that preserves 
the original object returned from the trap (while normalizing to a descriptor 
record for any internal calls on ordinary objects).  This preserves any exotic 
property descriptor object properties as is.  This seems like exactly the right 
things.  Such exotic property descriptor properties can only be meaningfully 
used by other proxy traps or application/library code that knows about them.  I 
don't see any need to normalize them into data properties or otherwise muck 
with what the actually implementor of the getOwnPropertyDescrptor trap choose 
to return. 

I this alternative implementation is, again, much simpler (and efficient) with 
fewer externally observable calls in its algorithm steps.  I sure you will want 
to review it so I will include it in the spec. draft.

It's all a matter of how much invariants we care to give up.

I think it's risky to allow descriptors to be returned whose attributes may be 
accessors, thus potentially fooling much existing ES5 code that often does 
simple tests like:

if (!desc.writable  !desc.configurable) {
  var val = desc.value; // we can assume the property is immutable, so we can 
cache its value
  ...
}

You can no longer rely on the correctness of such code if desc can't be 
guaranteed to be a plain old object containing only data properties.
 
 c) on the other hand is crucial for the non-configurability/non-extensibility 
 checks mentioned below. It's no use checking some invariants on a data 
 structure if that data structure can later still be mutated.

I don't see how an extra copy of the the result array makes any 

Fwd: possible excessive proxy invariants for Object.keys/etc??

2012-11-20 Thread Allen Wirfs-Brock
(for some reason the followup message didn't seem to make it to es-discuss the 
first time I redirected them.  so here goes using an alternative technique.  
Sorry in advance with we end up with duplicate messages)

Begin forwarded message:

 From: Tom Van Cutsem tomvc...@gmail.com
 Date: November 19, 2012 10:04:56 AM PST
 To: Allen Wirfs-Brock al...@wirfs-brock.com
 Cc: Mark S. Miller erig...@google.com, Jason Orendorff 
 jorendo...@mozilla.com
 Subject: Re: possible excessive proxy invariants for Object.keys/etc??
 
 Hi Allen,
 
 2012/11/18 Allen Wirfs-Brock al...@wirfs-brock.com
 The proxy spec.for Object.getOwnPropertyNames/kets/etc. seem to be doing 
 quite a bit more than this. They
 
 1) always copy the array returned from the trap?  Why is this necessary?  
 Sure the author of a trap should probably always return a fresh object but 
 not doing so doesn't violate the integrity of the frozen/sealed invariants?  
 In most cases they will provide a fresh object and  copying adds unnecessary  
 work  that is proportional to the number of names to every such call.
 
 The copying is to ensure:
 a) that the result is an Array
 b) that all the elements of the result are Strings
 c) to ensure the stability of the result.
 
 You can think of a + b as implementing a type coercion of the trap result to 
 Array of String. This coercion is not too dissimilar from what the 
 getOwnPropertyDescriptor has to do (normalization of the returned property 
 descriptor by creating a fresh copy).
 
 c) on the other hand is crucial for the non-configurability/non-extensibility 
 checks mentioned below. It's no use checking some invariants on a data 
 structure if that data structure can later still be mutated.
 
 If we don't care about any of a, b and c, then the result array wouldn't need 
 to be copied.
  
 2) ensuring that the list of property keys contains no duplicates.  Why is 
 this essential?  Again, I don't see what it has to do with the integrity of 
 the frozen/sealed invariants.  It is extra and probably unnecessary work that 
 is at least proportional to the number of names).
 
 We've been going back and forth over whether or not we wanted to prevent 
 duplicates. I remember Andreas Gal being concerned about these kinds of 
 issues (that was when he was doing the first Firefox prototype for old 
 proxies, in the context of the enumerate() trap, which was called during a 
 live for-in loop. IIRC, Firefox already did de-dupe checks, as properties 
 already enumerated in a child object should not be re-visited when visiting a 
 parent object)
 
 More recently, at the last TC39 meeting in Boston, we decided to change the 
 return type of the enumerate() trap from Array[String] to Iterator, and in 
 doing so waiving the duplicate properties check. Quoting from the Open 
 issues section of 
 http://wiki.ecmascript.org/doku.php?id=harmony:direct_proxies#open_issues:
 
 Enumerate trap signature: consider making the enumerate() trap return an 
 iterator rather than an array of strings. To retain the benefits of an 
 iterator (no need to store collection in memory), we might need to waive the 
 duplicate properties check. Resolution: accepted (duplicate properties check 
 is waived in favor of iterator return type)
 
 I guess if duplicate properties are not crucial for enumeration, they're also 
 not crucial for Object.getOwnPropertyNames and Object.keys and can be 
 dropped. Mark, can you comment?
  
 3) Every name in the list returned by the trap code is looked up on the 
 target to determine whether or not it exists, even if the target is 
 extensible.   Each of those lookup is observable (the target might itself be 
 a proxy) so, according to the algorithm they all must be performed.
 
 This is where we get into actual checks required to enforce 
 non-configurability/non-extensibility.
 
 Granted, the ES5 spec is not clear about the invariants on 
 getOwnPropertyNames and keys. The currently specified invariants are a 
 common-sense extrapolation of the existing invariants to cover these 
 operations.
 
 In practice, it determines the degree of confidence that a programmer can 
 have in Object.getOwnPropertyNames and friends when dealing with a frozen 
 object. If we waive these invariant checks, then the result of those 
 operations can never be trusted on to reliably introspect on a frozen 
 object's list of property names:
 
 Object.isFrozen(proxy) // true
 Object.getOwnPropertyNames(proxy) // ['foo']
 Object.getOwnPropertyNames(proxy) // [ ]
 
 Here, the 'foo' property apparently disappeared on a frozen object.
 
 If neither the for-in loop nor Object.getOwnPropertyNames nor Object.keys can 
 reliably report an object's own properties, then we've made it impossible to 
 reliably traverse and inspect a presumably deep-frozen object graph.
  
 4) Every own property of the target, is observably looked up (possibly a 
 second time) even if the object is extensible  and has no non-configurable 
 properties.
 
 We may

Fwd: possible excessive proxy invariants for Object.keys/etc??

2012-11-20 Thread Allen Wirfs-Brock


Begin forwarded message:

 From: Allen Wirfs-Brock al...@wirfs-brock.com
 Date: November 19, 2012 2:11:52 PM PST
 To: Tom Van Cutsem tomvc...@gmail.com
 Cc: Mark S. Miller erig...@google.com, Jason Orendorff 
 jorendo...@mozilla.com
 Subject: Re: possible excessive proxy invariants for Object.keys/etc??
 
 
 On Nov 19, 2012, at 10:04 AM, Tom Van Cutsem wrote:
 
 Hi Allen,
 
 2012/11/18 Allen Wirfs-Brock al...@wirfs-brock.com
 The proxy spec.for Object.getOwnPropertyNames/kets/etc. seem to be doing 
 quite a bit more than this. They
 
 1) always copy the array returned from the trap?  Why is this necessary?  
 Sure the author of a trap should probably always return a fresh object but 
 not doing so doesn't violate the integrity of the frozen/sealed invariants?  
 In most cases they will provide a fresh object and  copying adds unnecessary 
  work  that is proportional to the number of names to every such call.
 
 The copying is to ensure:
 a) that the result is an Array
 
 Why is Array-ness essential?  It was what ES5 specified, but ES5 had a fixed 
 implementations of Object.getOwnPropertyNames/keys so that requirement was 
 simply a reflection of what the  spec's algorithms actually did.  Most places 
 in the specification that consume an array only require array-like-ness, 
 not an actual array.  Now that we're make the implementation of the 
 getOPN/keys extensible, it would be natural to relax the requirement that 
 they produce a  [[Class]]===Array object.
 
 b) that all the elements of the result are Strings
 
 And presumably Symbols.  We have to also accommodate Symbols, at least for 
 getOwnPropetyNames.  Regardless, why is this important?  More below...
 
 c) to ensure the stability of the result.
 
 You can think of a + b as implementing a type coercion of the trap result to 
 Array of String. This coercion is not too dissimilar from what the 
 getOwnPropertyDescriptor has to do (normalization of the returned property 
 descriptor by creating a fresh copy).
 
 Yes, premature type coercion, in my opinion. Also, a classic performance 
 mistakes made by dynamic language programmers:  unnecessary coercion of 
 values that are never going to be access or redundant coercion checks of 
 values that are already of the property type.  Why is it important to do such 
 checks on values that are are just passing through these traps.  When and if 
 somebody actually gets arounds to using one of the elements that are returned 
 as a property key they will be automatically coerced to a valid value.  Why 
 is it important that it happens any sooner than that.
 
 getOwnPropertyDescriptor is also on my list to talk to you about for similar 
 reasons.  I don't see why the property descriptor needs to be normalized and 
 regenerated (including converting accessor properties on the descriptor into 
 data properties and requiring the [[Prototype]] to be object.  I have an 
 alternative for [[GetOwnProperty]]/TrapGetOwnPropertyDescriptor that 
 preserves the original object returned from the trap (while normalizing to a 
 descriptor record for any internal calls on ordinary objects).  This 
 preserves any exotic property descriptor object properties as is.  This seems 
 like exactly the right things.  Such exotic property descriptor properties 
 can only be meaningfully used by other proxy traps or application/library 
 code that knows about them.  I don't see any need to normalize them into data 
 properties or otherwise muck with what the actually implementor of the 
 getOwnPropertyDescrptor trap choose to return. 
 
 I this alternative implementation is, again, much simpler (and efficient) 
 with fewer externally observable calls in its algorithm steps.  I sure you 
 will want to review it so I will include it in the spec. draft.
 
 
 c) on the other hand is crucial for the 
 non-configurability/non-extensibility checks mentioned below. It's no use 
 checking some invariants on a data structure if that data structure can 
 later still be mutated.
 I don't see how an extra copy of the the result array makes any difference in 
 this regard  (also see below).   The array returned from 
 Object.getOwnPropertyNames is still mutable even after you make a copy. It's 
 only as stable as any other non-frozen object you are likely to encounter. 
 
 
 
 If we don't care about any of a, b and c, then the result array wouldn't 
 need to be copied.
 yes, I believe that should be the case.
 
  
 2) ensuring that the list of property keys contains no duplicates.  Why is 
 this essential?  Again, I don't see what it has to do with the integrity of 
 the frozen/sealed invariants.  It is extra and probably unnecessary work 
 that is at least proportional to the number of names).
 
 We've been going back and forth over whether or not we wanted to prevent 
 duplicates. I remember Andreas Gal being concerned about these kinds of 
 issues (that was when he was doing the first Firefox prototype for old 
 proxies, in the context

Fwd: possible excessive proxy invariants for Object.keys/etc??

2012-11-20 Thread Allen Wirfs-Brock


Begin forwarded message:

 From: Tom Van Cutsem tomvc...@gmail.com
 Date: November 20, 2012 11:36:24 AM PST
 To: Allen Wirfs-Brock al...@wirfs-brock.com
 Cc: Mark S. Miller erig...@google.com, Jason Orendorff 
 jorendo...@mozilla.com
 Subject: Re: possible excessive proxy invariants for Object.keys/etc??
 
 2012/11/19 Allen Wirfs-Brock al...@wirfs-brock.com
 On Nov 19, 2012, at 10:04 AM, Tom Van Cutsem wrote:
 The copying is to ensure:
 a) that the result is an Array
 
 Why is Array-ness essential?  It was what ES5 specified, but ES5 had a fixed 
 implementations of Object.getOwnPropertyNames/keys so that requirement was 
 simply a reflection of what the  spec's algorithms actually did.  Most places 
 in the specification that consume an array only require array-like-ness, 
 not an actual array.  Now that we're make the implementation of the 
 getOPN/keys extensible, it would be natural to relax the requirement that 
 they produce a  [[Class]]===Array object.
 
 It's all a matter of developer expectations and how much leeway we have in 
 changing the return type of existing built-ins.
 In theory, it's a backwards-incompatible change. In practice, it may not 
 matter.
 b) that all the elements of the result are Strings
 
 And presumably Symbols.  We have to also accommodate Symbols, at least for 
 getOwnPropetyNames.  Regardless, why is this important?  More below...
 
 Same argument as above.
 
 I recall there was some concern about symbols showing up in existing 
 reflection methods like Object.getOwnPropertyNames. Not sure how that got 
 resolved. It's basically touching upon the same issue of whether we can 
 change the return type of existing methods.
  
 
 c) to ensure the stability of the result.
 
 You can think of a + b as implementing a type coercion of the trap result to 
 Array of String. This coercion is not too dissimilar from what the 
 getOwnPropertyDescriptor has to do (normalization of the returned property 
 descriptor by creating a fresh copy).
 
 Yes, premature type coercion, in my opinion. Also, a classic performance 
 mistakes made by dynamic language programmers:  unnecessary coercion of 
 values that are never going to be access or redundant coercion checks of 
 values that are already of the property type.  Why is it important to do such 
 checks on values that are are just passing through these traps.  When and if 
 somebody actually gets arounds to using one of the elements that are returned 
 as a property key they will be automatically coerced to a valid value.  Why 
 is it important that it happens any sooner than that.
 
 I don't know if you are familiar with the work of Felleisen et al. on 
 higher-order contracts. In that work, they use the notion of blame between 
 different components/modules. Basically: if some module A receives some data 
 from a module B, and B provides wrong data, then B should be assigned 
 blame. You don't want to end up in a situation where A receives the blame at 
 the point where it passes that wrong data into another module C.
 
 The early type coercions at the exit of the traps can be thought of in 
 these terms: the invariant checks will always blame the proxy handler for 
 producing wrong data, at the point where the wrong data is produced and 
 before it's exposed to client code. Clients are expecting ES5/6 objects to 
 obey an implicit contract.
  
 getOwnPropertyDescriptor is also on my list to talk to you about for similar 
 reasons.  I don't see why the property descriptor needs to be normalized and 
 regenerated (including converting accessor properties on the descriptor into 
 data properties and requiring the [[Prototype]] to be object.  I have an 
 alternative for [[GetOwnProperty]]/TrapGetOwnPropertyDescriptor that 
 preserves the original object returned from the trap (while normalizing to a 
 descriptor record for any internal calls on ordinary objects).  This 
 preserves any exotic property descriptor object properties as is.  This seems 
 like exactly the right things.  Such exotic property descriptor properties 
 can only be meaningfully used by other proxy traps or application/library 
 code that knows about them.  I don't see any need to normalize them into data 
 properties or otherwise muck with what the actually implementor of the 
 getOwnPropertyDescrptor trap choose to return. 
 
 I this alternative implementation is, again, much simpler (and efficient) 
 with fewer externally observable calls in its algorithm steps.  I sure you 
 will want to review it so I will include it in the spec. draft.
 
 It's all a matter of how much invariants we care to give up.
 
 I think it's risky to allow descriptors to be returned whose attributes may 
 be accessors, thus potentially fooling much existing ES5 code that often does 
 simple tests like:
 
 if (!desc.writable  !desc.configurable) {
   var val = desc.value; // we can assume the property is immutable, so we can 
 cache its value
   ...
 }
 
 You can no longer rely

Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-20 Thread Brandon Benvie
In regards to the non-configurable/extensible issue, the issue is that the
proxy still needs to be *notified* of what's happening, but it's not really
allowed to *trap* because the result is predetermined. Currently this is
handled by treating it like a normal trap activation with extra limitations
on the return result. Skipping the trap entirely and returning the result
is undesirable because the notification is still important even when the
result can't be influenced.

The ideal result would be for the the trap to be called normally but as a
notification rather than as a request for something to happen/a return
value. That way a handler that needs side effects to happen can still make
sure they do, but there's no need to conjure up descriptors or reflect
actions where the result is predetermined.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-20 Thread Allen Wirfs-Brock
and my first reply, direct to es-discuss...

On Nov 20, 2012, at 2:32 PM, Allen Wirfs-Brock wrote:

 
 
 Begin forwarded message:
 
 From: Tom Van Cutsem tomvc...@gmail.com
 Date: November 20, 2012 11:36:24 AM PST
 To: Allen Wirfs-Brock al...@wirfs-brock.com
 Cc: Mark S. Miller erig...@google.com, Jason Orendorff 
 jorendo...@mozilla.com
 Subject: Re: possible excessive proxy invariants for Object.keys/etc??
 
 2012/11/19 Allen Wirfs-Brock al...@wirfs-brock.com
 On Nov 19, 2012, at 10:04 AM, Tom Van Cutsem wrote:
 The copying is to ensure:
 a) that the result is an Array
 
 Why is Array-ness essential?  It was what ES5 specified, but ES5 had a fixed 
 implementations of Object.getOwnPropertyNames/keys so that requirement was 
 simply a reflection of what the  spec's algorithms actually did.  Most 
 places in the specification that consume an array only require 
 array-like-ness, not an actual array.  Now that we're make the 
 implementation of the getOPN/keys extensible, it would be natural to relax 
 the requirement that they produce a  [[Class]]===Array object.
 
 It's all a matter of developer expectations and how much leeway we have in 
 changing the return type of existing built-ins.
 In theory, it's a backwards-incompatible change. In practice, it may not 
 matter.

It can't break existing code that doesn't use Proxies. Plus,  the default 
behavior is still to return a built-in Array instance.  For existing code to 
break it would have to:
1) be used in an environment where proxies existed and were being used
2) it would have to actually be reflecting upon such proxies
3) The proxy would have to return something other than a built-in array 
instance from the getOwnPropertyNames/keys trap.
4)  The code would actually have to be dependent upon the built-in array-ness 
(Array.isArray check, dependency upon the length invariant, etc.)  of such such 
a returned object.

It all seems quite unlikely to cause any compat issues for existing  and 
probably worth the risk.  Particularly if the alternative is to add an 
otherwise unnecessary array copying to every such proxy trap call. 

 b) that all the elements of the result are Strings
 
 And presumably Symbols.  We have to also accommodate Symbols, at least for 
 getOwnPropetyNames.  Regardless, why is this important?  More below...
 
 Same argument as above.
 
 I recall there was some concern about symbols showing up in existing 
 reflection methods like Object.getOwnPropertyNames. Not sure how that got 
 resolved. It's basically touching upon the same issue of whether we can 
 change the return type of existing methods.

I'm assuming we are excluding symbols from [[Enumerate]] and [[Keys]] so it is 
only [[GetOwnPropertyNames]] that have this concern.

One way or another we have to be able to reflectively get a list of symbol 
keyed properties.

We can either:
1) include them in the Object.getOwnPropertyNames result.
2) Consider getOwnPropertyNames depreciated (it actually lives forever) and 
replace it with a new Object.getOwnPropertyKeys that includes non-private 
Symbol keys
3) Keep getOwnPropertyNames as is and add Object.getOwnPropertySymbols that 
only returns the non-private-Symbol keys.

1) has the greatest backward compat concerns, but is the simplest to provide 
and for ES programmers to deal with going forward.
2) Eliminates the compat risk but creates perpetual potential for a: used 
gOPNames when I should have used gOPK  hazard.
3) Eliminates the compat risk but means everybody who wants to deal with all 
own properties have to deal with two lists of keys.  They also loose relative 
insertion order info relating key/symbol property keys.

Either 2 or 3 could require widening the MOP which increases the possibility 
for incomplete, inconsistent, or otherwise buggy proxies.  Even if we expose 
multiple public functions like either 2 or 3 I would still prefer to only have 
a single getOwnProperyyKeys internal method/trap that can be filtered to 
provide just strings and/or symbols.  Overall, I'm more concerned about keeping 
the internal method/trap MOP width as narrow as possible than I am about the 
size of the public Object.* API

  
 
 c) to ensure the stability of the result.
 
 You can think of a + b as implementing a type coercion of the trap result 
 to Array of String. This coercion is not too dissimilar from what the 
 getOwnPropertyDescriptor has to do (normalization of the returned property 
 descriptor by creating a fresh copy).
 
 Yes, premature type coercion, in my opinion. Also, a classic performance 
 mistakes made by dynamic language programmers:  unnecessary coercion of 
 values that are never going to be access or redundant coercion checks of 
 values that are already of the property type.  Why is it important to do 
 such checks on values that are are just passing through these traps.  When 
 and if somebody actually gets arounds to using one of the elements that are 
 returned as a property key they will be automatically

Re: possible excessive proxy invariants for Object.keys/etc??

2012-11-20 Thread Allen Wirfs-Brock

On Nov 20, 2012, at 3:16 PM, Brandon Benvie wrote:

 In regards to the non-configurable/extensible issue, the issue is that the 
 proxy still needs to be *notified* of what's happening, but it's not really 
 allowed to *trap* because the result is predetermined. Currently this is 
 handled by treating it like a normal trap activation with extra limitations 
 on the return result. Skipping the trap entirely and returning the result is 
 undesirable because the notification is still important even when the result 
 can't be influenced.
 
 The ideal result would be for the the trap to be called normally but as a 
 notification rather than as a request for something to happen/a return value. 
 That way a handler that needs side effects to happen can still make sure they 
 do, but there's no need to conjure up descriptors or reflect actions where 
 the result is predetermined.

right, I just made what I think is an equivalent suggestion in a new replay to 
Tom's last message.

Allen
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss