Re: [Proxies] Refactoring prototype climbing in the spec

2011-11-13 Thread Tom Van Cutsem
2011/11/10 Allen Wirfs-Brock al...@wirfs-brock.com


 On Nov 10, 2011, at 9:03 AM, Tom Van Cutsem wrote:

 Regarding property deletion: if an object is implemented as a proxy, and
 you would want to delete a property from that object, I'm not sure why you
 would want to circumvent triggering the delete trap?


 In
 http://wiki.ecmascript.org/doku.php?id=strawman:object_model_reformation I'm
 exploring explicitly distinguishing the semants of obj.propName and
 obj[expression] such that an object can explicitly define its
 obj[expression] behaviors without using a Proxy (note that currently  by
 the time a Proxy is called, the distinction is already lost so even if you
 wanted to use a Proxy for this purpose they may not be adequate).  In many
 cases (including the default), the object-specific  handler for
 obj[expression] will delegate back to Object.getProperty/Object.setProperty
 (either directly or via a super call).  But note that it can do so via
 direct [ ] syntax, as that would loop.  This can actually all be modeled
 with a new Reference variant within the spec. that distinguishes .
 references from [ ] references.

 However, I also need to account for the delete operator and distinguish
 delete obj.propName from delete obj[expression] .  This can be taken care
 of by the same reference extension (essentially References needs a delete
 method).  A handler for deleting obj[expression]] may also want to
 delegate back to normal property deletion and for the same reason as for
  obj[exper]  get/set handlers it can't directly use the syntactic form.
  Instead it needs to call an Object.deleteProperty function.


Understood.


 BTW, rather than adding these methods to Object, I'm beginning to think it
 might be better to import them from a built-in reflection module.


Indeed. Perhaps that built-in reflection module could be the same module
that defines the default forwarding handler. Your note that we need an
Object.deleteProperty method apart from the built-in syntax reminded me
that the default forwarding handler for proxies is really all about
providing method-based alternatives to things that can currently only be
achieved through built-in syntax.

In the direct proxies proposal, I proposed defining a Proxy.forward object
that enables forwarding all operations interceptable by proxies to another
object. A prototype implementation of it exists here:

http://code.google.com/p/es-lab/source/browse/trunk/src/proxies/DirectProxies.js#1250


If you observe closely, you'll note that the default forwarding API is
really the dual of the Proxy API.
Proxies uniformly turn all sorts of operations on objects (whether
triggered through syntax or built-in methods) into trap invocations, for
instance:
Object.getOwnPropertyDescriptor(proxy, name) =
handler.getOwnPropertyDescriptor(name, target)
name in proxy = handler.has(name, target)
etc.

The default forwarding API turns these trap invocations back into the
original operations:
Proxy.forward.getOwnPropertyDescriptor(name, target) =
Object.getOwnPropertyDescriptor(target, name);
Proxy.forward.has(name, target) = name in target
etc.

That's why the forwarding API is crucial for double lifting to work: if a
handler is itself a proxy, then to intercept handler[trapName], we need to
be able to generically forward the operation, which is made possible by
writing Proxy.forward[trapName].

I proposed the name Proxy.forward since that looks very natural when
writing handler code that simply wants to augment the default behavior:

funtion makeChangeLogger(target) {
  return Proxy.for(target, {
set: function(receiver, name, value, target) {
  log('property '+name+' on '+target+' set to '+value);
  return Proxy.forward.set(receiver, name, value, target);
}
  });}

However, it now seems to me that the methods encapsulated by Proxy.forward
can be more generally useful for arbitrary meta-programming, not just for
forwarding in the case of proxies.

I see an opportunity here to kill two birds with one stone: we can
introduce a reflection module (assume it's called Reflect for now) that
contains the Proxy.forward methods. That would:
a) obviate the need for Object.deleteProperty (now named Reflect.delete),
Object.getProperty (Reflect.get) and Object.setProperty (Reflect.set).
b) obviate the need for Proxy.forward (the above code snippet would call
Reflect.set instead, which is even shorter)

The design guideline for this Reflect module would be that the methods it
exposes have _exactly_ the same name + parameter list as the Proxy API trap
names. Not only does this retain consistency, it also enables easy double
lifting (or perhaps other design patterns that want to treat operations on
objects / Proxy traps generically).

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


Re: [Proxies] Refactoring prototype climbing in the spec

2011-11-10 Thread Tom Van Cutsem
2011/11/9 Allen Wirfs-Brock al...@wirfs-brock.com


 On Nov 9, 2011, at 3:53 AM, Tom Van Cutsem wrote:

 - lots of methods on Array.prototype (map, forEach, filter, some, reduce,
 reduceRight, reverse, splice, indexOf, lastIndexOf, every, shift, slice,
 sort, unshift): the only way in which these trigger proxy code is when
 |this| is a proxy, i.e. when they are called as
 Array.prototype.theMethod.call(aProxy).
 (calling aProxy.theMethod triggers the proxy's get trap)

 - Array.prototype.concat: [[HasProperty]] is called on a built-in Array
 only.


 the array methods are my primary concern as the HasProperty/Get
 combination is used to preserve holes as the algorithms iterate over
 arrays.  On large arrays, there can be lots of these calls.

 However, I'm not sure I understand your comments about
 theMethod.call(aProxy) vs. aProxy.theMethod(). In either case when
 theMethod is actually executed the this value must be aProxy and the
 internal calls to [[HasProperty]] and [[Get]] need to trap.


You're right, I forgot the get trap just traps property access, not the
full method invocation.

The get trap could return a bound method, binding theMethod's |this| to
the wrapped array, but that would break inheritance and would forego
intercepting the individual array elements accessed by the bound function.


 - 10.2.1.2 Object environment records uses [[HasProperty]] in a number of
 places. Isn't this needed only for |with|, so only triggered by |with
 (aProxy) { ... }|? Since ES.next builds on ES5/strict, this doesn't seem to
 carry much weight.


 And for global object bindings. It still has to work, consider for
 example, a proxy based DOM object that is accessed from non-Harmony code.
  The global object, it self, might be a Proxy.


I see. So IIUC, in such a runtime environment, dereferencing a global
variable name would then first trigger the global object's has trap,
potentially followed by the get trap.

Are you sure you want to kill [[HasProperty]] entirely? If we replace it by
a conditional [[Get]], wouldn't that mean that the expression |name in obj|
might unnecessarily trigger an accessor in obj?

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


Re: [Proxies] Refactoring prototype climbing in the spec

2011-11-10 Thread Tom Van Cutsem
2011/11/9 Allen Wirfs-Brock al...@wirfs-brock.com

 [[Get]] seems to do nothing but redispatch to [[GetP]] so its definition
 could be replaced with the body of [[GetP]].

 [[Puit] does a redispatch to [[SetP]] followed by a mode based
 conditional throw depending upon the result of the [[SetP]]. I din't think
 the the throwing behavior needs (or even should) be over-ride able by a
 proxy (or even by an alternative internal implementation). I would factor
 the conditional throw code out of  [[Put]] and make it the responsibility
 of the caller.  In practice, this just means that I would define a new
  Abstraction Operation that is used in place of direct calls to [[Put]].
  The abstraction operation wold essentially have the definition you provide
 for [[Put]] except that it would call [[Put]] instead of [[SetP]] and the
 definition of [[Put]] would be replaced with the body of [[SetP]]


Agreed. So if I understood all of that correctly, we would have:
- Abstract [[GetProperty]] and [[SetProperty]] operations (the methods I
called [[GetP]] and [[SetP]])
- Object.getProperty and Object.setProperty built-ins that call
[[GetProperty]] and [[SetProperty]]
- [[Get]] and [[Set]] methods on Objects that call [[GetProperty]] and
[[SetProperty]]
- [[Get]] and [[Set]] methods on Proxies that trigger get and set traps
- An abstract operation [[Put]](O, P, V, Throw) that calls
O.[[Set]](O,P,V) and performs the strict mode reject behavior.

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


Internal and external object APIs (was: [Proxies] Refactoring prototype climbing in the spec)

2011-11-10 Thread David Bruant

Le 10/11/2011 12:28, David Bruant a écrit :

(...)
but i think [traps] should be a right balance between the internal and 
external API.

Internal object API:
* getPropertyDescriptor(propName)
* setPropertyDescriptor(propName, desc) (more or less equivalent to the 
current [[DefineOwnProperty]])

* delete(name)
* getPropertyNames()
* makeNonExtensible()
* getPrototype()
* getDefaultValue(hint)
* getClass()

I would claim that anything done in the ES5.1 spec with objects 
(functions aside for now) could be expressed as a combinaison of this 
minimal internal object API. Some choices are intentional 
(makeNonExtensible does not have a makeExtensible counterpart, 
get{Prototype|Class} not having a set counterpart...).
Also, I do not write getOwnPropertyNames, because as far as an 
ECMAScript object is concerned, there is no reason to do something else 
than adding an own property. Oh yes, there is this other object you 
can have a reference to by calling getPrototype, but there is no 
reason to act on this one directly internally.


I'd like to emphasis that this minimal API defines objects as a mapping 
of name - property descriptors.



External object API:
** Current
* Object.getOwnPropertyDescriptor(o, name)
* Object.getOwnPropertyNames(o)
* Object.defineProperty(o, name, pd)
* delete o.name
* Object.freeze(o)
* Object.seal(o)
* Object.preventExtensions(o)
* name in o
* ({}).hasOwnProperty.call(o, name)
* o.name
* o.name = val
* for (name in o)
* Object.keys(o)
** Upcoming
* for(v of o)
* (I'm probably forgetting some)


Allen wrote:
More generally, I think there should be a 1::1 correspondence between 
the internal methods in listed in ES5 Table 8 and fundamental proxy traps.
If by fundamental, you were refering to something like the minimal 
internal API I described above, once again, I disagree, but for 
different reasons that before. First, I think that there is an agreement 
to not trap some things like getPrototype, getClass or getDefaultValue.
Then, I think that if some traps (like set or get) exist, it's 
because it's a bit more convenient to reason on object interaction from 
the syntax perspective than the fundamental internal API. Actually, 
proxies initial design rather makes a correspondance with syntax [1].


Regarding ES5 invariants, these were expressed in terms of internal API 
opening the door to host object to do whatever they want in their 
[[Get]] and [[Put]] internal methods. I'm glad to see invariants being 
defined more closely to the syntax view of objects in the direct proxies 
proposal [2]


David

[1] http://wiki.ecmascript.org/doku.php?id=harmony:proxies#api
[2] 
http://wiki.ecmascript.org/doku.php?id=strawman:direct_proxies#invariant_enforcement

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


Re: [Proxies] Refactoring prototype climbing in the spec

2011-11-10 Thread Allen Wirfs-Brock

On Nov 10, 2011, at 1:36 AM, Tom Van Cutsem wrote:

 2011/11/9 Allen Wirfs-Brock al...@wirfs-brock.com
 [[Get]] seems to do nothing but redispatch to [[GetP]] so its definition 
 could be replaced with the body of [[GetP]].
 
 [[Puit] does a redispatch to [[SetP]] followed by a mode based conditional 
 throw depending upon the result of the [[SetP]]. I din't think the the 
 throwing behavior needs (or even should) be over-ride able by a proxy (or 
 even by an alternative internal implementation). I would factor the 
 conditional throw code out of  [[Put]] and make it the responsibility of the 
 caller.  In practice, this just means that I would define a new  Abstraction 
 Operation that is used in place of direct calls to [[Put]].  The abstraction 
 operation wold essentially have the definition you provide for [[Put]] except 
 that it would call [[Put]] instead of [[SetP]] and the definition of [[Put]] 
 would be replaced with the body of [[SetP]]
 
 Agreed. So if I understood all of that correctly, we would have:
 - Abstract [[GetProperty]] and [[SetProperty]] operations (the methods I 
 called [[GetP]] and [[SetP]])

Yes, current spec. conventions would just call these GetProperty and 
SetProperty abstract operations. 

 - Object.getProperty and Object.setProperty built-ins that call 
 [[GetProperty]] and [[SetProperty]]

Also, to fully reify property manipulation I think we also need to factor 
[[Delete]] in a similar manner and provide an Object.deleteProperty built-in 
that calls the DeleteProperty abstraction operations.

I touch upon this in 
http://wiki.ecmascript.org/doku.php?id=strawman:object_model_reformation#a_side_note_on_reflective_property_access
 (note that this stawman is still under construction)

the basic reason is that just like with Get/Put a handler may want to invoke 
the primitive behavior of Delete upon the target object without going through 
the delete operator (which could retrigger a trap).

 - [[Get]] and [[Set]] methods on Objects that call [[GetProperty]] and 
 [[SetProperty]]
 - [[Get]] and [[Set]] methods on Proxies that trigger get and set traps

Yes, although I prefer to think of [[Get]] and [[Set]] consistently for both 
Proxy and normal objects.  They are polymorphic traps that dispatch to a 
handler that is determined by the nature of the object.  For native objects 
[[Get]] and [[Set]] dispatch to handlers that just call GetProperty or 
SetProperty

 - An abstract operation [[Put]](O, P, V, Throw) that calls O.[[Set]](O,P,V) 
 and performs the strict mode reject behavior.

Yes, call it Put.


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


Re: [Proxies] Refactoring prototype climbing in the spec

2011-11-10 Thread Allen Wirfs-Brock

On Nov 10, 2011, at 1:26 AM, Tom Van Cutsem wrote:

 
 Are you sure you want to kill [[HasProperty]] entirely? If we replace it by a 
 conditional [[Get]], wouldn't that mean that the expression |name in obj| 
 might unnecessarily trigger an accessor in obj?
 

Good point, I didn't think about the fact that [[Get]]  always triggers 
accessor calls.

We probably do need to continue to have a side-effect free [[HasProperty]].  I 
still think it is desirable to have a conditional [[Get]] available for use in 
places like the array algorithms. Whether it is an over-roading of the [[Get]] 
api or an additional trap is debatable.

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


Re: [Proxies] Refactoring prototype climbing in the spec

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


 On Nov 10, 2011, at 1:36 AM, Tom Van Cutsem wrote:

 - Object.getProperty and Object.setProperty built-ins that call
 [[GetProperty]] and [[SetProperty]]


 Also, to fully reify property manipulation I think we also need to factor
 [[Delete]] in a similar manner and provide an Object.deleteProperty
 built-in that calls the DeleteProperty abstraction operations.

 I touch upon this in
 http://wiki.ecmascript.org/doku.php?id=strawman:object_model_reformation#a_side_note_on_reflective_property_access
  (note
 that this stawman is still under construction)

 the basic reason is that just like with Get/Put a handler may want to
 invoke the primitive behavior of Delete upon the target object without
 going through the delete operator (which could retrigger a trap).


Actually I was mistaken: the above quoted line should read:

- Object.getProperty and Object.setProperty built-ins that call the [[Get]]
and [[Set]] methods

In other words: it's important that Object.getProperty(aProxy, name)
triggers that proxy's get trap rather than performing the Object
algorithm and calling the getOwnPropertyDescriptor trap.
Otherwise, proxies would not compose well (think of a proxy p1 wrapping
another proxy p2: if p1 forwards a property access to its target (p2), p2's
get trap should be triggered).
(+ we could end up with duplicated getOwnPropertyDescriptor calls, as
pointed out by David earlier)

If the goal is to intentionally avoid proxy traps, one can write up the
algorithm in Javascript itself (as I have done on the strawman page). But I
think it's important that Object.getProperty does trigger proxy traps (if
only for consistency: Object.getOwnPropertyDescriptor et al. also trigger
proxy traps).

Regarding property deletion: if an object is implemented as a proxy, and
you would want to delete a property from that object, I'm not sure why you
would want to circumvent triggering the delete trap?

 - [[Get]] and [[Set]] methods on Objects that call [[GetProperty]] and
 [[SetProperty]]
 - [[Get]] and [[Set]] methods on Proxies that trigger get and set traps


 Yes, although I prefer to think of [[Get]] and [[Set]] consistently for
 both Proxy and normal objects.  They are polymorphic traps that
 dispatch to a handler that is determined by the nature of the object.  For
 native objects [[Get]] and [[Set]] dispatch to handlers that just call
 GetProperty or SetProperty


Do you mean that the direction you would like to go is to look at normal
ES5 objects as proxies with a special, built-in handler?

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


Re: [Proxies] Refactoring prototype climbing in the spec

2011-11-10 Thread Allen Wirfs-Brock

On Nov 10, 2011, at 3:28 AM, David Bruant wrote:

 Le 09/11/2011 12:17, Tom Van Cutsem a écrit :
 
 2011/11/8 Allen Wirfs-Brock al...@wirfs-brock.com
  
 More generally, I think there should be a 1::1 correspondence between the 
 internal methods in listed in ES5 Table 8 and fundamental proxy traps.
 
 I absolutely agree we should strive to achieve this.
 I disagree.
 
 First of all, Table 8 is incomplete:
 * It lacks a function for property enumeration and proxies need a trap for 
 that (for-in loops, Object.getOwnPropertyNames, Object.keys).
 * There is no method for passing [[Extensible]] from true to false, though 
 this behavior is used and needs a (fundamental) trap as well. The reason 
 for this is certainly that this action can be described in one spec algorithm 
 step, so there was no need from a specification perspective to consider 
 this as an internal method, but it's still a fundamental operation you can 
 perform on an object.
 (I may be missing others)
 

I agree that Table 8 is incomplete (and has unnecessary items in it). The point 
is that Table 8 should define the fundamental Object semantic API that is used 
by all clients, including the specifications of language feature semantics, the 
specification of built-in functions,  and the semantics that are reified via 
the Proxy and Object reflection API.  One consistent set of object semantics 
operations, used by everybody.

 A second point I disagree on is the idea of fundamental trap. This notion 
 existed on the original proxy proposal. I think it was more for the purpose 
 of writing traps more easily. With the direct proxies proposal, the notion of 
 fundamental and derived traps disappears (and hopefully, direct proxies will 
 be promoted during the next TC-39 meeting).

I was using fundamental  to mean what i just stated above.  I agree that only 
these fundamental object operations need to be reflected in the Proxy API.

 
 Regardless of Table 8 being incomplete, I think that proxy traps have another 
 factor to take into account which is the relationship with surface syntax. 
 When someone writes let a = o.a;, the intention is to call the get 
 operation regardless of whether the a property is on o or somewhere on its 
 prototype chain. This is another thing that I like in the [[Get]] 
 refactoring: when the prototype is the proxy, its get trap gets called and 
 not its getOwnPropertyDescriptor trap. It makes proxy traps more in line with 
 the object clients requests.

The surface syntax perspective is exactly how I conceptualize the Table 8 
level of the specification. It is the interface between the runtime object 
model and the surface features of the language.  

However, there were some practical engineering considerations that went into 
the ES5 factoring of the internal methods. For example, [[Put]] calls 
[[DefineOwnProperty]] to set a property's value because it made it easier to 
specify Array behavior.  Creating an array indexed property (possibly via 
[[Put]]) and letting the value of the length property both have side-effects. 
 There are multiple ways that such values can be set, including using 
Object.defineProperty.  By making the default implementation of [[Put]] 
delegate to [[DefineOwnProperty]] I only needed to over-ride 
[[DefineOwnProperty]] for array instances to specify their semantics.  If I 
hand't done this, I would have had to consistently over-ridden both 
[[DefineOwnProperty]] and [[Put]].

As long, as the internal methods were just specification devices, this sort 
of refactoring could be done as a convenience.  But as soon as the reify them 
via traps we have to thing about the broader and permanent impacts of such 
refactoring.

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


Re: [Proxies] Refactoring prototype climbing in the spec

2011-11-10 Thread Allen Wirfs-Brock

On Nov 10, 2011, at 9:03 AM, Tom Van Cutsem wrote:

 2011/11/10 Allen Wirfs-Brock al...@wirfs-brock.com
 
 On Nov 10, 2011, at 1:36 AM, Tom Van Cutsem wrote:
 - Object.getProperty and Object.setProperty built-ins that call 
 [[GetProperty]] and [[SetProperty]]
 
 Also, to fully reify property manipulation I think we also need to factor 
 [[Delete]] in a similar manner and provide an Object.deleteProperty built-in 
 that calls the DeleteProperty abstraction operations.
 
 I touch upon this in 
 http://wiki.ecmascript.org/doku.php?id=strawman:object_model_reformation#a_side_note_on_reflective_property_access
  (note that this stawman is still under construction)
 
 the basic reason is that just like with Get/Put a handler may want to invoke 
 the primitive behavior of Delete upon the target object without going through 
 the delete operator (which could retrigger a trap).
 
 Actually I was mistaken: the above quoted line should read:
 - Object.getProperty and Object.setProperty built-ins that call the [[Get]] 
 and [[Set]] methods
 
 In other words: it's important that Object.getProperty(aProxy, name) triggers 
 that proxy's get trap rather than performing the Object algorithm and 
 calling the getOwnPropertyDescriptor trap.
 Otherwise, proxies would not compose well (think of a proxy p1 wrapping 
 another proxy p2: if p1 forwards a property access to its target (p2), p2's 
 get trap should be triggered).
 (+ we could end up with duplicated getOwnPropertyDescriptor calls, as pointed 
 out by David earlier)
 
 If the goal is to intentionally avoid proxy traps, one can write up the 
 algorithm in Javascript itself (as I have done on the strawman page). But I 
 think it's important that Object.getProperty does trigger proxy traps (if 
 only for consistency: Object.getOwnPropertyDescriptor et al. also trigger 
 proxy traps).

Yes, on further thought, I agree that Object getProperty should trigger the 
trap.

 
 Regarding property deletion: if an object is implemented as a proxy, and you 
 would want to delete a property from that object, I'm not sure why you would 
 want to circumvent triggering the delete trap?

In http://wiki.ecmascript.org/doku.php?id=strawman:object_model_reformation I'm 
exploring explicitly distinguishing the semants of obj.propName and 
obj[expression] such that an object can explicitly define its obj[expression] 
behaviors without using a Proxy (note that currently  by the time a Proxy is 
called, the distinction is already lost so even if you wanted to use a Proxy 
for this purpose they may not be adequate).  In many cases (including the 
default), the object-specific  handler for obj[expression] will delegate back 
to Object.getProperty/Object.setProperty (either directly or via a super call). 
 But note that it can do so via direct [ ] syntax, as that would loop.  This 
can actually all be modeled with a new Reference variant within the spec. that 
distinguishes . references from [ ] references.

However, I also need to account for the delete operator and distinguish delete 
obj.propName from delete obj[expression] .  This can be taken care of by the 
same reference extension (essentially References needs a delete method).  A 
handler for deleting obj[expression]] may also want to delegate back to normal 
property deletion and for the same reason as for  obj[exper]  get/set handlers 
it can't directly use the syntactic form.  Instead it needs to call an 
Object.deleteProperty function.

BTW, rather than adding these methods to Object, I'm beginning to think it 
might be better to import them from a built-in reflection module.

 - [[Get]] and [[Set]] methods on Objects that call [[GetProperty]] and 
 [[SetProperty]]
 - [[Get]] and [[Set]] methods on Proxies that trigger get and set traps
 
 Yes, although I prefer to think of [[Get]] and [[Set]] consistently for both 
 Proxy and normal objects.  They are polymorphic traps that dispatch to a 
 handler that is determined by the nature of the object.  For native objects 
 [[Get]] and [[Set]] dispatch to handlers that just call GetProperty or 
 SetProperty
 
 Do you mean that the direction you would like to go is to look at normal ES5 
 objects as proxies with a special, built-in handler?

Yes, exactly.  BTW, I think this was probably the intent of the originally 
internal methods and native+host objects design.

allen



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


Re: [Proxies] Refactoring prototype climbing in the spec

2011-11-09 Thread Tom Van Cutsem
2011/11/8 Allen Wirfs-Brock al...@wirfs-brock.com

 I don't think that [[GetP]] and [[PutP]] need to be internal methods
 In spec'ing this I think I would make them be abstract operations.
 Internal methods are extensions points that can be over-ridden on a per
 object basis.  That is what [[Get]] and [[Put]] provides.  GetP and SetP
 define fixed operations.


I proposed [[GetP]] and [[SetP]] as internal methods because Proxies would
inherit the built-in behavior for [[Get]] and [[Put]], but override the
[[GetP]] and [[SetP]] operations. If [[GetP]] and [[SetP]] become abstract
operations, won't they need to explicitly dispatch? Proxies could override
[[Get]] and [[Put]], but that would require them to duplicate the Object
[[Get]] and [[Put]] code.


 More generally, I think there should be a 1::1 correspondence between the
 internal methods in listed in ES5 Table 8 and fundamental proxy traps.


I absolutely agree we should strive to achieve this.

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


Re: [Proxies] Refactoring prototype climbing in the spec

2011-11-09 Thread Tom Van Cutsem
2011/11/8 Allen Wirfs-Brock al...@wirfs-brock.com

 On Nov 8, 2011, at 7:33 AM, Andreas Rossberg wrote:
  But I have a follow-up request. :) Regarding redundant trap calls with
  proxies there is another, more pervasive problem with the current
  spec: in lots of places it first calls [[HasProperty]] and then
  [[Get]]. With proxies, this always implies two trap calls, which seems
  wasteful. Would it be possible to refactor that, too?
 
  Seems more difficult, because we would need to enable [[Get]] (and
  hence the get trap) to signal lookup failure.  (Too bad that we cannot
  reuse `undefined' for it.) But I think the current situation isn't
  satisfactory.

 I agree, the current specification style is fine when we are dealing with
 side-effectly free internal operations but as soon as they are reified they
 become problematic and a performance issue.


Is the situation really that problematic?
Skimming the ES5.1 spec for [[HasProperty]], I encounter calls in the
following places:

- ToPropertyDescriptor conversion (only triggers proxy code via
Object.defineProperty(obj, name, aProxyAsDescriptor) and
Object.defineProperties).

- lots of methods on Array.prototype (map, forEach, filter, some, reduce,
reduceRight, reverse, splice, indexOf, lastIndexOf, every, shift, slice,
sort, unshift): the only way in which these trigger proxy code is when
|this| is a proxy, i.e. when they are called as
Array.prototype.theMethod.call(aProxy).
(calling aProxy.theMethod triggers the proxy's get trap)

- Array.prototype.concat: [[HasProperty]] is called on a built-in Array
only.

- 10.2.1.2 Object environment records uses [[HasProperty]] in a number of
places. Isn't this needed only for |with|, so only triggered by |with
(aProxy) { ... }|? Since ES.next builds on ES5/strict, this doesn't seem to
carry much weight.

- The in operator: only calls [[HasProperty]], not followed by a call to
[[Get]] (so it's not an instance of the conditional [[Get]] pattern).

None of the conditional [[Get]] patterns on proxies seem particularly
common operations, even if proxies would be widely used. Are they worth the
complexity of changing one of the most critical and common operations in
Javascript?

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


Re: [Proxies] Refactoring prototype climbing in the spec

2011-11-09 Thread Allen Wirfs-Brock

On Nov 9, 2011, at 3:53 AM, Tom Van Cutsem wrote:

 2011/11/8 Allen Wirfs-Brock al...@wirfs-brock.com
 On Nov 8, 2011, at 7:33 AM, Andreas Rossberg wrote:
  But I have a follow-up request. :) Regarding redundant trap calls with
  proxies there is another, more pervasive problem with the current
  spec: in lots of places it first calls [[HasProperty]] and then
  [[Get]]. With proxies, this always implies two trap calls, which seems
  wasteful. Would it be possible to refactor that, too?
 
  Seems more difficult, because we would need to enable [[Get]] (and
  hence the get trap) to signal lookup failure.  (Too bad that we cannot
  reuse `undefined' for it.) But I think the current situation isn't
  satisfactory.
 
 I agree, the current specification style is fine when we are dealing with 
 side-effectly free internal operations but as soon as they are reified they 
 become problematic and a performance issue.
 
 Is the situation really that problematic?
 Skimming the ES5.1 spec for [[HasProperty]], I encounter calls in the 
 following places:
 
 - ToPropertyDescriptor conversion (only triggers proxy code via 
 Object.defineProperty(obj, name, aProxyAsDescriptor) and 
 Object.defineProperties).
 
 - lots of methods on Array.prototype (map, forEach, filter, some, reduce, 
 reduceRight, reverse, splice, indexOf, lastIndexOf, every, shift, slice, 
 sort, unshift): the only way in which these trigger proxy code is when |this| 
 is a proxy, i.e. when they are called as 
 Array.prototype.theMethod.call(aProxy).
 (calling aProxy.theMethod triggers the proxy's get trap)
 
 - Array.prototype.concat: [[HasProperty]] is called on a built-in Array only.

the array methods are my primary concern as the HasProperty/Get combination is 
used to preserve holes as the algorithms iterate over arrays.  On large 
arrays, there can be lots of these calls.

However, I'm not sure I understand your comments about theMethod.call(aProxy) 
vs. aProxy.theMethod(). In either case when theMethod is actually executed the 
this value must be aProxy and the internal calls to [[HasProperty]] and [[Get]] 
need to trap. 

 
 - 10.2.1.2 Object environment records uses [[HasProperty]] in a number of 
 places. Isn't this needed only for |with|, so only triggered by |with 
 (aProxy) { ... }|? Since ES.next builds on ES5/strict, this doesn't seem to 
 carry much weight.

And for global object bindings. It still has to work, consider for example, a 
proxy based DOM object that is accessed from non-Harmony code.  The global 
object, it self, might be a Proxy.

 
 - The in operator: only calls [[HasProperty]], not followed by a call to 
 [[Get]] (so it's not an instance of the conditional [[Get]] pattern).
 
 None of the conditional [[Get]] patterns on proxies seem particularly common 
 operations, even if proxies would be widely used. Are they worth the 
 complexity of changing one of the most critical and common operations in 
 Javascript?

The array functions are my primary concern.

Allen

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


Re: [Proxies] Refactoring prototype climbing in the spec

2011-11-09 Thread Allen Wirfs-Brock

On Nov 9, 2011, at 3:17 AM, Tom Van Cutsem wrote:

 2011/11/8 Allen Wirfs-Brock al...@wirfs-brock.com
 I don't think that [[GetP]] and [[PutP]] need to be internal methods
 In spec'ing this I think I would make them be abstract operations. Internal 
 methods are extensions points that can be over-ridden on a per object basis.  
 That is what [[Get]] and [[Put]] provides.  GetP and SetP define fixed 
 operations.
 
 I proposed [[GetP]] and [[SetP]] as internal methods because Proxies would 
 inherit the built-in behavior for [[Get]] and [[Put]], but override the 
 [[GetP]] and [[SetP]] operations. If [[GetP]] and [[SetP]] become abstract 
 operations, won't they need to explicitly dispatch? Proxies could override 
 [[Get]] and [[Put]], but that would require them to duplicate the Object 
 [[Get]] and [[Put]] code.

[[Get]] seems to do nothing but redispatch to [[GetP]] so its definition could 
be replaced with the body of [[GetP]].

[[Puit] does a redispatch to [[SetP]] followed by a mode based conditional 
throw depending upon the result of the [[SetP]]. I din't think the the throwing 
behavior needs (or even should) be over-ride able by a proxy (or even by an 
alternative internal implementation). I would factor the conditional throw code 
out of  [[Put]] and make it the responsibility of the caller.  In practice, 
this just means that I would define a new  Abstraction Operation that is used 
in place of direct calls to [[Put]].  The abstraction operation wold 
essentially have the definition you provide for [[Put]] except that it would 
call [[Put]] instead of [[SetP]] and the definition of [[Put]] would be 
replaced with the body of [[SetP]]


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


Re: [Proxies] Refactoring prototype climbing in the spec

2011-11-08 Thread Tom Van Cutsem

 I am a big fan of this refactoring.
 I like the idea that the algorithm transfers full control to the proxy.
 Also, accepting this strawman would solve my inherited event properties
 problem because I would have access to the receiver from the get trap
 and would be able to do the binding I want.


Glad to hear that.


 About [[SetP]]:
 * It seems to me that we've traded a duplicated [[GetProperty]] call for
 a duplicated [[GetOwnProperty]] (Step 1 and 5.a) call on the receiver.
 This could be avoided by storing the property descriptor at the
 beginning (when O.[[setP]](Receiver, P, V) is called and O ===
 receiver). Step 5.a could be remove by the change.


The double [[GetOwnProperty]] invocation on the initial receiver should not
be observable: if the initial Receiver of [[SetP]] is a proxy, the proxy's
[[SetP]] algorithm (which triggers the set trap) executes instead of this
algorithm. So it's only if the initial Receiver is a normal object that
this code executes, and then the call to [[GetOwnProperty]] on line 1 will
never trigger proxy code.

When [[SetP]] is called by evaluating a property assignment expression,
Receiver also always denotes a normal non-proxy object. However, with the
proposed Object.getProperty built-in one can write:

Object.getProperty(aProxy, name, aNormalObject)

which would trigger aNormalObject.[[SetP]](aProxy, name), so then Receiver
would indeed be a proxy. Line 1 then calls
aNormalObject.[[GetOwnProperty]], while line 5.a, if reached, would trigger
aProxy.[[GetOwnProperty]].

Long story short: the O variable in the [[SetP]] algorithm always denotes
a normal non-proxy object. In general, the Receiver variable can be any
object.


 * If step 5.a is removed, I think that step 5.b.i is useless, because we
 would have returned from the set when O was the receiver (by step 2.a of
 [[setP]])
 * If step 5.a is removed, then step 5.c is useless, because if the desc
 had a [[set]], then we would have already returned from one of the
 substep of step 3 when O was the receiver

 Why not redefining [[Get]] as what you have defined as [[GetP]] and
 equivalent for [[Set]] and [[SetP]]?
 Current 8.12.3 [[Get]] (P) would become [[Get]] (Receiver, P). It would
 be called with O as initial value for Receiver pretty much everywhere in
 the spec except within [[Get]] recursive calls.
 Equivalent for [[Set]].
 It would prevent the replacement of 2 Object.* methods by 2 others.


The reason I introduced separate [[GetP]] and [[SetP]] methods is simply so
that the public API of Objects remained intact. Your suggestion is
reasonable: trade proliferation of built-in methods for a small public API
change in the spec. I guess this is just a matter of find/replacing all the
calls to [[Get]]/[[Put]]. Might even be an opportunity to get rid of put
and use set consistently throughout the spec.


 With the refactoring, on the direct proxy strawman, I don't think we
 need the proxy argument for the get and set traps anymore. It was here
 as the receiver, but since we have the receiver itself, the get and set
 trap can just have the receiver and the target as argument.


Good point. I'd wager that in most use cases, knowing that |receiver| is
either your own proxy or a descendant of that proxy is sufficient. I can't
currently think of a use case where the get/set trap would really want to
be able to access the proxy itself, not just the proxy or a descendant.
That doesn't mean that use cases for it don't exist, however. I guess if
access to the proxy is really needed, it's easy enough to accomplish:

var p = Proxy.for(target, handler);
handler.proxy = p;

Now the proxy is accessible as |this.proxy| in all traps. This may seem
like a hassle, but if the use cases for accessing a proxy are sufficiently
minor, getting rid of the proxy argument to the get/set traps seems like a
good tradeoff.

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


Re: [Proxies] Refactoring prototype climbing in the spec

2011-11-08 Thread Andreas Rossberg
On 7 November 2011 16:54, Tom Van Cutsem tomvc...@gmail.com wrote:
 I wrote up an initial (but fairly complete) draft of a proposed refactoring
 of the ES5 [[Get]], [[Put]] and [[HasProperty]] algorithms to change the way
 in which these algorithms climb the prototype
 chain: http://wiki.ecmascript.org/doku.php?id=strawman:refactoring_put

Looks good, and as far as I can see from a first read, solves the
issues we were discussing so far.

But I have a follow-up request. :) Regarding redundant trap calls with
proxies there is another, more pervasive problem with the current
spec: in lots of places it first calls [[HasProperty]] and then
[[Get]]. With proxies, this always implies two trap calls, which seems
wasteful. Would it be possible to refactor that, too?

Seems more difficult, because we would need to enable [[Get]] (and
hence the get trap) to signal lookup failure.  (Too bad that we cannot
reuse `undefined' for it.) But I think the current situation isn't
satisfactory.

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


Re: [Proxies] Refactoring prototype climbing in the spec

2011-11-08 Thread David Bruant
Le 08/11/2011 11:54, Tom Van Cutsem a écrit :
  

 About [[SetP]]:
 * It seems to me that we've traded a duplicated [[GetProperty]]
 call for
 a duplicated [[GetOwnProperty]] (Step 1 and 5.a) call on the receiver.
 This could be avoided by storing the property descriptor at the
 beginning (when O.[[setP]](Receiver, P, V) is called and O ===
 receiver). Step 5.a could be remove by the change.


 The double [[GetOwnProperty]] invocation on the initial receiver
 should not be observable: if the initial Receiver of [[SetP]] is a
 proxy, the proxy's [[SetP]] algorithm (which triggers the set trap)
 executes instead of this algorithm.
Very true. And even if there is no trap, the default action is to
trigger [[Set]] on the target, so no duplicated call.

 (...)

 Long story short: the O variable in the [[SetP]] algorithm always
 denotes a normal non-proxy object. In general, the Receiver variable
 can be any object.
  

 * If step 5.a is removed, I think that step 5.b.i is useless,
 because we
 would have returned from the set when O was the receiver (by step
 2.a of
 [[setP]])
 * If step 5.a is removed, then step 5.c is useless, because if the
 desc
 had a [[set]], then we would have already returned from one of the
 substep of step 3 when O was the receiver

 Why not redefining [[Get]] as what you have defined as [[GetP]] and
 equivalent for [[Set]] and [[SetP]]?
 Current 8.12.3 [[Get]] (P) would become [[Get]] (Receiver, P). It
 would
 be called with O as initial value for Receiver pretty much
 everywhere in
 the spec except within [[Get]] recursive calls.
 Equivalent for [[Set]].
 It would prevent the replacement of 2 Object.* methods by 2 others.


 The reason I introduced separate [[GetP]] and [[SetP]] methods is
 simply so that the public API of Objects remained intact. Your
 suggestion is reasonable: trade proliferation of built-in methods for
 a small public API change in the spec. I guess this is just a matter
 of find/replacing all the calls to [[Get]]/[[Put]].
Exactly, that's what I had in mind.

 Might even be an opportunity to get rid of put and use set
 consistently throughout the spec.
I cannot agree more with this idea. Especially with proxies having a
set trap and accessor properties having setters, [[Put]] sounds
wrong even though that has been the name in ES5, ES3 (and even before?)


 With the refactoring, on the direct proxy strawman, I don't think we
 need the proxy argument for the get and set traps anymore. It
 was here
 as the receiver, but since we have the receiver itself, the get
 and set
 trap can just have the receiver and the target as argument.


 Good point. I'd wager that in most use cases, knowing that |receiver|
 is either your own proxy or a descendant of that proxy is
 sufficient. I can't currently think of a use case where the get/set
 trap would really want to be able to access the proxy itself, not just
 the proxy or a descendant.That doesn't mean that use cases for it
 don't exist, however.
Oh true, I thought that proxy and the receiver were the same objects but
if the proxy is on the prototype, it is not the case.

 I guess if access to the proxy is really needed, it's easy enough to
 accomplish:

 var p = Proxy.for(target, handler);
 handler.proxy = p;
Indeed.

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


Re: [Proxies] Refactoring prototype climbing in the spec

2011-11-08 Thread Allen Wirfs-Brock
This is all going in a good direction.

I only have a few minor comments:

I don't think that [[GetP]] and [[PutP]] need to be internal methods
In spec'ing this I think I would make them be abstract operations. Internal 
methods are extensions points that can be over-ridden on a per object basis.  
That is what [[Get]] and [[Put]] provides.  GetP and SetP define fixed 
operations.

More generally, I think there should be a 1::1 correspondence between the 
internal methods in listed in ES5 Table 8 and fundamental proxy traps. We 
either need to eliminate any internal methods that don't trap or add 
corresponding traps.  In this proposal you eliminate the need for [[CanPUt]] 
and you raise the question of whether that is possible for also get rid of 
[[GetProperty]].  My analysis 
(https://docs.google.com/spreadsheet/ccc?key=0Ak51JfLL8QLYdDFkcy1VUl9OQ3BSc1kxeDI4RkJsc0E
 ) says that we can, so we should just go ahead and eliminate it. 

We might even consider eliminating [[Delete]] by defining 
[[DefneOwnProperty]](name,undefined) to mean delete. 

Finally, I also have some thoughts about [[HasProperty]] but I will put those 
in a replay to Andreas message on that touches on that.

Allen




On Nov 7, 2011, at 7:54 AM, Tom Van Cutsem wrote:

 Hi,
 
 I wrote up an initial (but fairly complete) draft of a proposed refactoring 
 of the ES5 [[Get]], [[Put]] and [[HasProperty]] algorithms to change the way 
 in which these algorithms climb the prototype chain: 
 http://wiki.ecmascript.org/doku.php?id=strawman:refactoring_put
 
 This is mainly beneficial for proxies, as the prototype walking strategy 
 becomes observable to proxies-used-as-prototypes.
 
 IMHO, the refactored algorithms interoperate with proxies in a much saner 
 way, finally restoring the intuitive semantics of the get and set traps 
 that MarkM and I had in mind from the beginning, but which Sean Eagan pointed 
 out were flawed given the ES5 spec algorithms.
 
 The biggest change is in the [[Put]] algorithm. For those not into ES spec 
 language, I wrote up the behavior for ES5 [[Put]] and my proposed ES.next 
 [[Put]] in JS itself:
 ES5 [[Put]]: 
 http://code.google.com/p/es-lab/source/browse/trunk/src/es5adapt/setProperty.js#115
 Proposed ES.next [[Put]]: 
 http://code.google.com/p/es-lab/source/browse/trunk/src/es5adapt/setProperty.js#68
 
 The refactored version also fixes the anomalies resulting from the ES5 
 [[CanPut]] vs. [[Put]] split that Andreas Rossberg pointed out earlier on 
 this list.
 
 When I say refactoring here, I really do intend for these new algorithms to 
 be equivalent to the ES5 algorithms for non-proxy objects. To test whether 
 these algorithms are indeed equivalent, I wrote up a little test-suite that 
 runs in the browser: 
 http://es-lab.googlecode.com/svn/trunk/src/es5adapt/testSetProperty.html
 
 The results look promising (success on Firefox7, 1 failure on Chrome/Safari 
 because these allow overriding of non-writable inherited data props, haven't 
 tested other browsers yet). Still, the more es-discuss eye-balls that can 
 scrutinize these algorithms, the better.
 
 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: [Proxies] Refactoring prototype climbing in the spec

2011-11-08 Thread Allen Wirfs-Brock

On Nov 8, 2011, at 7:33 AM, Andreas Rossberg wrote:

 On 7 November 2011 16:54, Tom Van Cutsem tomvc...@gmail.com wrote:
 I wrote up an initial (but fairly complete) draft of a proposed refactoring
 of the ES5 [[Get]], [[Put]] and [[HasProperty]] algorithms to change the way
 in which these algorithms climb the prototype
 chain: http://wiki.ecmascript.org/doku.php?id=strawman:refactoring_put
 
 Looks good, and as far as I can see from a first read, solves the
 issues we were discussing so far.
 
 But I have a follow-up request. :) Regarding redundant trap calls with
 proxies there is another, more pervasive problem with the current
 spec: in lots of places it first calls [[HasProperty]] and then
 [[Get]]. With proxies, this always implies two trap calls, which seems
 wasteful. Would it be possible to refactor that, too?
 
 Seems more difficult, because we would need to enable [[Get]] (and
 hence the get trap) to signal lookup failure.  (Too bad that we cannot
 reuse `undefined' for it.) But I think the current situation isn't
 satisfactory.

I agree, the current specification style is fine when we are dealing with 
side-effectly free internal operations but as soon as they are reified they 
become problematic and a performance issue.

I believe that the [[HasProperty]] [[Get]] combination is always used in 
situations where a conditional [[Get]] is desired.  I suggest that we 
redefine [[Get]] to take a second optional argument which is used as a signal 
value to indicated that the property does not exist.  Internally (within the 
specification) any unique object value can be used as the signal value as the 
spec. will never allow that value to escape such that it could be stored as a 
property value.

A similar approach could be taken with the trap and Object.getProperty APIs but 
there is the hazard that handler code might capture and misuse (store into a 
property) the signal value.  It isn't clear to me whether this would constitute 
an exploitable hazard or whether it would just be an annoying bug.  This 
capture problem could be avoid if the trap always passed a new object to the 
handler when the [[Get]] call uses its second argument.  I'm reluctant to 
impose an (even trivial) object allocation on [[Get]] traps but it probably is 
still less overhead then making two traps.  Also, it would not be needed in 
situations where the [[Get]] only had a single argument.

Using this approach, the get handler signature could be something like: 
function(receiver, name, target, proxy, missingMarker=undefined)
and the signature for Object.getProperty could be: function(receiver, name, 
missingMarker=undefined, parent=receiver)
(for the optional argument ordering, I'm assuming that use of a missingMarker 
is more common then using an explicit parent)

Given the limitations of ES function protocol the moral equivalent of either 
reference parameters or multiple value returns also require an object 
allocation.  It isn't clear that we can do much better than this style of API. 
If we do this we should be able to eliminate both the [[HasProperty]] internal 
method and the has trap.

allen


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


[Proxies] Refactoring prototype climbing in the spec

2011-11-07 Thread Tom Van Cutsem
Hi,

I wrote up an initial (but fairly complete) draft of a proposed refactoring
of the ES5 [[Get]], [[Put]] and [[HasProperty]] algorithms to change the
way in which these algorithms climb the prototype chain: 
http://wiki.ecmascript.org/doku.php?id=strawman:refactoring_put

This is mainly beneficial for proxies, as the prototype walking strategy
becomes observable to proxies-used-as-prototypes.

IMHO, the refactored algorithms interoperate with proxies in a much saner
way, finally restoring the intuitive semantics of the get and set traps
that MarkM and I had in mind from the beginning, but which Sean Eagan
pointed out were flawed given the ES5 spec algorithms.

The biggest change is in the [[Put]] algorithm. For those not into ES spec
language, I wrote up the behavior for ES5 [[Put]] and my proposed ES.next
[[Put]] in JS itself:
ES5 [[Put]]: 
http://code.google.com/p/es-lab/source/browse/trunk/src/es5adapt/setProperty.js#115

Proposed ES.next [[Put]]: 
http://code.google.com/p/es-lab/source/browse/trunk/src/es5adapt/setProperty.js#68


The refactored version also fixes the anomalies resulting from the ES5
[[CanPut]] vs. [[Put]] split that Andreas Rossberg pointed out earlier on
this list.

When I say refactoring here, I really do intend for these new algorithms
to be equivalent to the ES5 algorithms for non-proxy objects. To test
whether these algorithms are indeed equivalent, I wrote up a little
test-suite that runs in the browser: 
http://es-lab.googlecode.com/svn/trunk/src/es5adapt/testSetProperty.html

The results look promising (success on Firefox7, 1 failure on Chrome/Safari
because these allow overriding of non-writable inherited data props,
haven't tested other browsers yet). Still, the more es-discuss eye-balls
that can scrutinize these algorithms, the better.

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


Re: [Proxies] Refactoring prototype climbing in the spec

2011-11-07 Thread David Bruant
Hi Tom,

Thanks for all this work!

Le 07/11/2011 16:54, Tom Van Cutsem a écrit :
 Hi,

 I wrote up an initial (but fairly complete) draft of a proposed
 refactoring of the ES5 [[Get]], [[Put]] and [[HasProperty]] algorithms
 to change the way in which these algorithms climb the prototype
 chain: http://wiki.ecmascript.org/doku.php?id=strawman:refactoring_put

 This is mainly beneficial for proxies, as the prototype walking
 strategy becomes observable to proxies-used-as-prototypes.

 IMHO, the refactored algorithms interoperate with proxies in a much
 saner way, finally restoring the intuitive semantics of the get and
 set traps that MarkM and I had in mind from the beginning, but which
 Sean Eagan pointed out were flawed given the ES5 spec algorithms.
I am a big fan of this refactoring.
I like the idea that the algorithm transfers full control to the proxy.
Also, accepting this strawman would solve my inherited event properties
problem because I would have access to the receiver from the get trap
and would be able to do the binding I want.

About [[SetP]]:
* It seems to me that we've traded a duplicated [[GetProperty]] call for
a duplicated [[GetOwnProperty]] (Step 1 and 5.a) call on the receiver.
This could be avoided by storing the property descriptor at the
beginning (when O.[[setP]](Receiver, P, V) is called and O ===
receiver). Step 5.a could be remove by the change.
* If step 5.a is removed, I think that step 5.b.i is useless, because we
would have returned from the set when O was the receiver (by step 2.a of
[[setP]])
* If step 5.a is removed, then step 5.c is useless, because if the desc
had a [[set]], then we would have already returned from one of the
substep of step 3 when O was the receiver

Why not redefining [[Get]] as what you have defined as [[GetP]] and
equivalent for [[Set]] and [[SetP]]?
Current 8.12.3 [[Get]] (P) would become [[Get]] (Receiver, P). It would
be called with O as initial value for Receiver pretty much everywhere in
the spec except within [[Get]] recursive calls.
Equivalent for [[Set]].
It would prevent the replacement of 2 Object.* methods by 2 others.

With the refactoring, on the direct proxy strawman, I don't think we
need the proxy argument for the get and set traps anymore. It was here
as the receiver, but since we have the receiver itself, the get and set
trap can just have the receiver and the target as argument.

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