Proxy Inception

After marinating for a few months, my JSConf.eu slides:

(Mobile/No-Flash version)

These are based directly on the excellent work of Mark Miller and Tom Van Cutsem, who developed the harmony:proxies proposal that is now approved for the next major iteration of the JavaScript standard (ECMA-262, probably edition 6 but we’ve learned the hard way not to number prematurely — anyway, approved for “ECMAScript Harmony” [my original Harmony-coining post]).

Harmony Proxies are already prototyped in Firefox 4 betas, thanks to Andreas Gal.

When I reached the “meta-level shifting” slide:

meta-level-shifting

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:

selective-interception

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 [1].

But when you need to go backstage of the dream and change the rules without breaking the dreamer’s illusion, by interceding on every get, set, call, 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 noSuchMethod or 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.

/be

[1] 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”

  1. Firefox 4 is using Proxies to implement all of its security wrappers

    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 (__get__, __set__, __noSuchProperty__, __count__, __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 noSuchMethod with 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 isCall flag for get ,)

    Dmitry.

  2. 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.

    https://blog.calyptus.eu/seb/2010/11/javascript-proxies-leaky-this/

    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.

  3. 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.

    /be

  4. 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.

Leave a Reply to Dmitry A. Soshnikov Cancel reply

Your email address will not be published. Required fields are marked *