<div class="gmail_quote">2012/11/14 Allen Wirfs-Brock <span dir="ltr"><<a href="mailto:allen@wirfs-brock.com" target="_blank">allen@wirfs-brock.com</a>></span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div style="word-wrap:break-word"><br><div><div><div class="h5"><div>On Nov 13, 2012, at 12:25 PM, Tom Van Cutsem wrote:</div><blockquote type="cite"><div class="gmail_quote"><div>It's dawning on me that the main reason I dislike adding flags to the fundamental traps is that it breaks the 1-to-1 symmetry with the operations that they intercept:</div>

<div><br></div><div>Object.getOwnPropertyDescriptor(proxy, name) // traps as getOwnPropertyDescriptor(target, name)</div><div><br></div><div>This symmetry should make it relatively easy for an ES5 programmer to pick up the handler API. The signatures look familiar (at least for all operations that are expressed as function calls). Adding extra flags breaks the symmetry.</div>
</div></blockquote><div><br></div></div></div><div>Interesting, the 1-to-1 symmetry I've been look for is between the internal methods and the proxy traps.  To me, that is the MOP and things like Object.getOwnPropertyDescriptor are a connivence layer a level above the MOP.   From that perspective, it feels fine to me to have a MOP operation (a trap or internal method), called say, CheckOwnProperty that has a flag argument that controls whether you want to get a property descriptor or a boolean result.   That MOP operation can be used at the language level to implement the in operator and other language level-semantics and at the library level to implement convenience functions such as O.p.hasOwnProperty and Object.getOwnPropertyDescriptor.  The MOP programmer   (whether implementing ordinary objects in the implementation, host objects using low level extension points or using Proxy to implement exotic objects)r sits in the middle between those two layers.  All they really need to know about is the MOP.</div>
</div></div></blockquote><div><br></div><div>I think I understand your point of view. I'll try to restate it differently:</div><div><br></div><div>You are arguing for 2 levels of abstraction ("layers"):</div>
<div>- Most JS developers are "base-level" programmers: they use ES5 APIs like Object.getOwnPropertyDescriptor to reflect on their objects.</div><div>- A small fraction of JS developers will be "meta-level" programmers: these include at least proxy authors and host object authors. These programmers would use a *different* API, i.e. the MOP, which consists of methods such as a "checkOwnProperty" trap and presumably a corresponding Reflect.checkOwnProperty method. There would be a correspondence between the base-level API and the internal MOP methods, but this correspondence is not a straightforward 1-to-1 correspondence.</div>
<div><br></div><div>Now, there are two routes to optimize for, with opposite pay-offs:</div><div>1) Make the MOP API correspond as much as possible to the base-level ES5 API. This benefits ES5 programmers, who can easily pick up the meta-level API as it's recognizable, at the expense of ES6 meta-level programmers, who must deal with a larger API surface (incl. the burden to keep fundamental and derived traps in sync).</div>
<div><br></div><div>2) Make the MOP API as minimal as possible. This benefits ES6 meta-programmers, but at the expense of increasing the learning curve for ES5 programmers to become ES6 meta-level programmers (because the difference between base-level and meta-level API will necessarily be bigger)</div>
<div><br></div><div>Approach 1) corresponds roughly to the current setup with fundamental + derived traps.</div><div>Approach 2) corresponds roughly to "provide only fundamental traps".</div><div><br></div><div>
Now consider an ES6 meta-programmer interested in intercepting the "in"-operator.</div><div><br></div><div>Given approach 1) she can look at the full list of traps (e.g. the list at the top of <<a href="http://wiki.ecmascript.org/doku.php?id=harmony:direct_proxies">http://wiki.ecmascript.org/doku.php?id=harmony:direct_proxies</a>>) and quickly figure out that she must implement the "has" trap.</div>
<div><br></div><div>Given approach 2), our meta-programmer must figure out that the "in"-operator in fact calls the "getOwnPropertyDescriptor" trap instead, and tests for its result to be undefined or not.</div>
<div><br></div><div>In effect, approach 2) requires that meta-programmers understand the default implementation of the derived traps (i.e. this code: <<a href="http://wiki.ecmascript.org/doku.php?id=harmony:virtual_object_api#non-normative_implementation">http://wiki.ecmascript.org/doku.php?id=harmony:virtual_object_api#non-normative_implementation</a>>) before being able to intercept a derived operation.</div>
<div><br></div><div>To be fair, if our meta-programmer in approach 1) implements the "has" trap, and that trap is not a simple before/after/around method that forwards to the target, then she must also override "getOwnPropertyDescriptor" to return consistent results. If she subclassed Handler (and we make the fundamental traps abstract methods again), she'll get an exception prompting her to investigate further. If she did not subclass Handler, she just shot herself in the foot. So eventually, she will have to learn about distinction between fundamental and derived methods anyway.</div>
<div><br></div><div>The difference between approach 1) and 2) is at what point you must learn about the differences.</div><div><br></div><div>Approach 1) favors ES5 programmers. Approach 2) favors ES6 meta-programmers. I think we should optimize for ES5 programmers.</div>
<div><br></div><div>Cheers,</div><div>Tom</div></div>