2011/1/27 David Bruant <bru...@enseirb-matmeca.fr> > Le 27/01/2011 11:20, Tom Van Cutsem a écrit : > > - Agreed that if we contemplate adding 'proxy' as an argument to > getPropertyDescriptor and getPropertyNames, we should add it to all other > traps as well. > - Agreed that this is the simplest way of allowing a shared handler to get > at the proxy it's currently 'serving' > - W.r.t. a handler not being able to perform typeof/instanceof on the proxy > it's intercepting: this does have the benefit of detracting programmers from > writing handlers that act differently for function vs object proxies. But > agreed that this functionality might be needed to fix the quirky behavior of > a host object. > > This last point is actually a concern. Is the (one?) point of proxies to > being able to fully emulate (and by 'emulate', I also mean 'fix') host > objects. If so, proxies should have access to all internal > methods&properties. As said in ES5 8.6.2 right under Table 8: > "Every object (including host objects) must implement all of the internal > properties listed in Table 8.". If we want to be able to emulate proxies, we > need to be as powerful with proxies. > Question is: do we want to? > > I have recently been working on emulating Arrays (they are host objects, > aren't they?) with proxies and native objects. I'll put the code on github > and provide a longer feedback in another e-mail, but the basic idea was to > use a forwarding proxy and implement the only method that matters: > defineProperty. I have almost blindly implemented+adapted > [[defineOwnProperty]] (ES5 15.4.5.1). > Everything works perfectly so far. There are a few differences with native > arrays, though: > - I have no control over the [[class]] internal property, so even though my > "proxyArrays" act like native ones, they can be discriminated quite easily. >
Right, this issue has come up before. From the "open issues" on the proxies wiki page: *TC39 Meeting 1/28/10 *The number of operators that proxies can virtualize is still open for discussion. The current proposal does not allow proxies to virtualize typeof and [[Class]]. Perhaps these could be virtualized but kept constant by passing appropriate values for typeof and [[Class]] to the Proxy constructor. The alternative API<http://wiki.ecmascript.org/doku.php?id=strawman:uniform_proxies> does virtualize typeof in this manner. *TC39 Meeting 3/24/10 *The experimental third className parameter to Proxy.create in spidermonkey should not be standardized. Objects should not be able to virtualize the [[Class]] built-in property. However, Object.prototype.toString.call(proxy) will reveal proxies if the object they are proxying has a non-Object or non-Function [[Class]]. There is concern within the committee that overriding [[Class]] may violate spec. invariants. I believe it is Allen's intention to take issues like this into account in his MOP refactoring (Allen, correct me if I'm wrong). IMHO, I think being able to override the [[Class]] at least for toString() purposes will be required for proxies to fully fix/emulate existing host objects. - I haven't tested, but according to the semantics of Array initialisers > (ES5 11.1.4), "[]" calls "new Array() where Array is the standard built-in > constructor with that name.". So even if I try window.Array = proxyArray, > "[]" should not create one of my arrays. This sounds perfectly fair. > - I obviously initialize my proxyArrays with Array.prototype as prototype. > I haven't tested if it works; it is allowed not to, because in ES5, under > each array prototype method is written: > " The *** function is intentionally generic; it does not require that its > this value be an Array object. Therefore it can be transferred to other > kinds of objects for use as a method. Whether the *** function can be > applied successfully to a host object is implementation-dependent. ". > They could be reimplemented if needed to fully emulate Arrays. (I've worked > on that a billion years ago : > https://github.com/DavidBruant/ecma5array/blob/test_conformance/ecma5array.js > ) > > So here is another question on proxies goal/rational: > Should proxies be powerful enough to fully emulate native Arrays? (If so > and if ES Harmony has proxies in it, then native Array could be specified as > a proxy which is awesome and a half in my opinion, but that's a different > problem). > As Brendan pointed out, Arrays are not host objects, they are much more privileged and part of the core language. To elaborate on Brendan's response, I think the point of Allen's MOP-refactoring is to structure the spec. such that ES-harmony has a very well-defined internal object hierarchy, and proxies are the mechanism by which JS developers can hook into that hierarchy. All existing built-ins (Object, String, Array, ...) are part of the predefined internal object hierarchy. They could or could not be defined in terms of proxies & handlers, but even if they would be, their traps would still be defined in terms of spec. language, not in terms of pure JS, to avoid over-specification and to allow for efficient internal representations. That said, it would be very nice if the behavior of all built-ins can in fact be emulated via proxies. I can imagine that a tutorial on ES-harmony could then explain the behavior of built-ins by showing example code similar to your Array emulation code. Cheers, Tom > > > > Re. adding 'proxy' as an optional last parameter to all traps: what > worries me is that for some traps, this could be terribly confusing. > Consider: > > Object.getOwnPropertyDescriptor(proxy, name); > // will trap as: > getOwnPropertyDescriptor: function(name, proxy) { ... } > > The reversed argument order is going to bite people. > Adding 'proxy' as a last optional argument is confusing in this way > for get{Own}PropertyDescriptor, defineProperty, delete, hasOwn > It's OK for get{Own}PropertyNames, keys, fix, has, enumerate > get and set would then take 4 arguments, and it's unclear to me whether > tacking 'proxy' to the front or to the back is better. > (alternatively, maybe 'get' and 'set' don't need access to the proxy after > all. It seems to me that if 'receiver' has multiple proxies in its prototype > chain, only the one closest to receiver is going to trigger a handler > get/set trap. OTOH, without a built-in Proxy.isTrapping(obj) method, I don't > think the handler can find out what object on the prototype chain is a > proxy) > > We could choose to add 'proxy' at the "right" place in the argument list > depending on the trap. This trades one kind of cognitive load (unexpected > argument order for some traps) for another (no uniform position of 'proxy' > across all traps, and no longer an optional argument for all traps). Either > way, we need to decide whether this added API complexity is worth it. > > One more thing: giving the handler access to its proxy by default may > increase chances of runaway recursion hazards, as every operation that the > handler performs on its own proxy is going to call some trap on the handler > itself. Ideally, we should be able to label the 'proxy' parameter with a big > red warning sign saying "handle with care!". I ran into this problem already > a couple of times when writing "get" traps. The 'receiver' parameter often > is the proxy itself, and doing even simple things like trying to print the > proxy (e.g. for debugging) will call proxy.toString, hence will recursively > call the "get" trap you're trying to debug. But maybe the problem is just > more exaggerated in the "get" trap since property access is so common, and > it won't really be an issue for the other traps. > > I had already read that point in your proxy tutorial. It will be up to the > resources that people go to to learn how proxies work to tell them that they > should be careful with unwanted recursion. > One important such resource is very likely to be the MDN page. I'll take > care of writing down all these points. Otherwise, it's a wiki, feel free to > jump in anytime to correct things or add examples. > > Cheers, > > David > > > > Cheers, > Tom > > 2011/1/26 Brendan Eich <bren...@mozilla.com> > >> On Jan 26, 2011, at 11:02 AM, David Bruant wrote: >> >> >> On the question of proxy parameters for all traps (well, receiver for >> get and set): fewer args are better, and closure capture of proxy by handler >> avoids leaking the proxy to handler friends, if that matters. Likewise you >> can't get the handler from the proxy. >> > If you handlers are frozen, there should be no leaking, shouldn't there? >> (I actually think that freezing the handler should be done in the no-op >> forwarding proxy example or any handler factory, but that's another issue). >> >> No default freezing is going to be imposed. :-| >> >> >> > About the closure capturing, it works only if one proxy is using the >> handler. It doesn't if several proxies share it. >> >> Good point. >> >> >> >> These aren't absolute arguments, but I remember working through the >> alternative of a leading proxy parameter, both as JS hacker using proxies >> and in terms of SpiderMonkey's C++ implementation, and it was just bigger >> and less tidy, for both "sides" (JS and C++), without enough payoff. >> > ... what about a trailing proxy parameter? It won't change anything on >> the C++ side (by comparison to a leading parameter), but will on the JS >> side, because you can omit the parameter if you don't need it. >> >> Not a bad idea, and the C++ gurus can take it. Tom, Mark? >> >> /be > > > >
_______________________________________________ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss