After marinating for a few months, my JSConf.eu slides:
Harmony Proxies are already prototyped in Firefox 4 betas, thanks to Andreas Gal.
When I reached the “meta-level shifting” slide:
someone in the audience tweeted about how my talk was like Inception (github-sourced simulator). Meta-meta dreams within dreams (warning: meta-to-the-4th-shifting leads to Limbo).
The money-shot slide in my view is:
which depicts how Proxies finally level the playing field between browser implementors using burned-into-browser-binaries C++ and web developers using downloaded JS.
It’s hard to overstate how this matters. The DOM (IE’s for sure, but all of them, back to the original I hacked in Netscape 2) suffers from its “VM territory” privileges, which have been abused to make all kinds of odd-ball “host objects”. Proxies both greatly reduce the weirdness of host objects and let JS hackers emulate and even implement such objects.
Novice JS hackers and all JS programmers happy at the base level of the language need not worry about the details of Proxies. Proxies cannot break the invariants that keep the JS lucid dream unfolding on stage. Specifically, you can’t hack traps onto an existing non-proxy object — you can only create a new proxy and start using it afresh, perhaps passing it off as a preexisting kind of object that it emulates .
But when you need to go backstage of the dream and change the rules without breaking the dreamer’s illusion, by interceding on every
construct, etc., then Proxies are indispensable.
Firefox 4 is using Proxies to implement all of its security wrappers.
Long-time SpiderMonkey fans will ask “why no
__noSuchMethod__” (or: why not also have a
invoke trap, or a flag to
get telling when it is trapping a get for the entire callee part of a call expression)? The short answer is to keep the set of handler traps minimal in terms of JS semantics (modulo scalability), which do not include “invoke-only methods”. The longer answer is on es-discuss.
 Inside the engine, a clever trick from Smalltalk called
becomes is used to swap a newborn Proxy and an existing object that has arbitrarily many live references. Thus an object requiring no behavioral intercession can avoid the overhead of traps until it escapes from a same-origin or same-thread context, and only if it does escape through a barrier will it become a trapping Proxy whose handler accesses the original object after performing access control checks or mutual exclusion.
The local jargon for such object/Proxy swapping is “brain transplants”.
9 Replies to “Proxy Inception”
I let myself to mention in addition another useful and interesting stuff which we can do with using proxies (my personal experiments):
1. Delegation based mixins (combination of vertical and horizontal inheritance);
2. Pythonic __magic__ properties (
__delete__,etc) placed directly on objects. Of course, it’s a mixing of meta- and normal- level, however, may be useful for quick convenient scripting in own projects;
3. A stratified meta- and normal- levels useful wrappers (or meta-meta-meta inception — one level before the Limbo ;)) with optimized
noSuchMethodwith using only one function-activator (apply invariant is supported);
4. Array negative indicies making convenient to refer array elements from the end.
Playing a bit with proxies, I think they really be a good future of the ES.
P.S.: though, I personally be glad for
Dmitry: cool, I am especially glad about item 4 — a way to opt into negative indexing via a library. Is your experimental code on github?
Yep, thanks, Brendan. My current experiments are in the es-laboratory github’s repo. And in particular — negative array indicies.
WP’s link style in these comments is clearly too subtle for me :-P.
I just want to point out that it’s important for any code that expects to be wrapped in a proxy to consider what instance it needs to work with. This is the well known problem of having two different instances.
Using certain patterns the handler instance may leak outside the proxy in unexpected ways and vice versa. While it should be seamless for the consumer of a proxy, that only holds true if the handler object have properly considered these patterns.
Sebastian: I replied on your blog, you make a good point. Wrappers require more care (and more primitives, including WeakMaps) to avoid leaking the wrapped objects.
Sebastian: I should have pointed out that the example in my slides, slide 78 in full (starting at slide 74), “Example: Membranes”, properly wraps any captured unwrapped |this| references, by wrapping methods, etc., transitively. New post on this, it’s worth clarifying. No weakmaps in that slide, so too many wrappers may be created, but that was not your point. |this| won’t be leaked with such a membrance, is my point.
Right. Interesting. The trick is to proxy specific objects going in as well as out.
You don’t even need to wrap everything in a context. Membranes can be used even for a single proxy while everything else remains intact.
The proxy would have to unwrap some instances while traveling back out of the proxy but that should be fairly trivial.
Thanks for spreading the word on proxies, Brendan. For those that like to see some simple example code using Proxies, I’m gathering examples at https://soft.vub.ac.be/~tvcutsem/proxies