Direct proxies update

David Bruant bruant.d at gmail.com
Tue Nov 29 06:17:48 PST 2011


Le 29/11/2011 12:00, Tom Van Cutsem a écrit :
> 2011/11/29 Allen Wirfs-Brock <allen at wirfs-brock.com
> <mailto:allen at wirfs-brock.com>>
Thanks for your explanations in the other message.

>     The only issue that I know of relates to the fact that access to
>     remote objects state probably requires the use of async APIs and
>     call backs while all of the Mirror APIs I have ever seen are most
>     naturally expressed in a synchronous style.  I'm not sure what the
>     best resolution of that issue will be.  It certainly would be
>     possible to make an async mirrors API that also works with local
>     objects.  Anybody writing code that needed to work with any kind
>     of mirror would want to use that async API.  However, that would
>     be awkward and expensive for cases where you know that synchronous
>     access is possible, such as probably most Proxy uses of reflection.
>
I went to the same sort of reflection when I thought about how node.js
models I/O. The initial intention (which is still strongly there but a
bit changed) is that when you manipulate something in memory, you do
something synchronous ("var a = f();"), but when doing an I/O, you do
something asynchronous ("f(function(a){});"). This is a very elegant
model, but what when the database is on memory?

I think that we (node, Mirror API, a lot of people in the JavaScript
community) are trying to achieve 2 goals that do not seem really going
well together:
1) uniform API
2) support for both synchronous and asynchronous

It seems to me that 2) imposes programming styles that impact APIs
(returning a function or passing the result of a call as an argument of
the given callback).

I can't think of any language that is able to do both.

>     Perhaps for those cases a simpler synchronous mirrors API is
>     needed.  Unfortunately, that would leave us with two variants of
>     the mirrors API.
>
>
> I agree with your analysis. Having both sync and async variants of the
> mirrors API is unfortunate, but I think it's absolutely necessary if
> you want mirrors to work with remote objects. I think most on this
> list will agree that hiding asynchrony is to be avoided.
I agree. Since it does not seem possible to do both and that we don't
want to impose synchronisity, having 2 APIs seems to be the way to go,
unfortunately (unless my analysis is wrong or someone comes up with a
genius idea to support uniform API for sync and async)

> But perhaps the sync and async mirror APIs could be developed such
> that there is a trivial (perhaps mechanical) conversion between both.
> (If we would have promises, the async API could be the sync API with
> some (return) types lifted from T to Promise<T>)
>
> My position at this time is that Mirrors are promising, but the
> details still need to be worked out (especially re. remote objects)
> and it's a pretty big design exercise. Therefore, this may be a task
> better left to userland libraries in the short term.
>  
>
>     BTW, it occurs to me that there probably is a similar issue if
>     anyone tries to use Proxy to actually create a remote object
>     access facade.   Proxy Handler calls are synchronous but what if a
>     trap handler (say a get) needs to make an async call to a to
>     obtain the state needed to produce the value returned by the trap... 
>
>
> Yes, two relevant points with respect to this:
> 1) Mark and I tried to express something like this: an "eventual"
> reference to a local object, enforcing asynchronous access to its
> target. The example is on the old harmony:proxies page:
> <http://wiki.ecmascript.org/doku.php?id=harmony:proxies#an_eventual_reference_proxy>
>
> This code depends on promises (the "get" trap returns a promise for
> the result) and basically enables only synchronous access to
> properties known to be non-configurable or non-writable. It's a good
> example of a piece of code that exploits the new ES5 "invariants" to
> be able to safely cache immutable properties.
>
> Promises are really the abstraction you want to bridge synchronous
> APIs with asynchronous operation.
Promises sounds promising, but I'm not sure it will entirely fill the
gap. If we're trying to write a function f which works both with local
and remote objects, we end up with this:
-----
function f(o){
    var a = o.bla;
    // In the synchronous case, a is the value.
    // if o is a localFarReferenceMaker, a is a promise.

    // In order to continue for both cases, one would have to do
something like:
    if(isPromise(a)){
         a.when(function(res){
             // do something with the value in res
         });
    }
    else{
         // do the exact same thing with the value in a
    }
}
-----

Obviously, an idea is to factorize the common behavior:
-----
function f(o){
    var a = o.bla;
    // In the synchronous case, a is the value.
    // if o is a localFarReferenceMaker, a is a promise.

    function g(res){
        // do something with the value in res
    }

    if(isPromise(a)){
         a.when(g);
    }
    else{
         g(a);
    }
}
-----

And we get to some canonical case where I don't know how to uniformize
"a.when(g)" and "g(a)". Maybe something with generators? Maybe a new
form a function?

Maybe the goal of trying to have a function which works with both local
and remote values is vain (in general or in JavaScript in particular)?

> 2) When layering remote objects over a restful API, ideally you want
> obj[name] to perform an HTTP GET and obj.name <http://obj.name>(a,b,c)
> to perform an HTTP POST. Proxies cannot distinguish property access
> from method invocation (which is just get+apply), so they currently
> can't perform the above mapping.
Hence the "bang" ("!") syntax, I guess.
I think proxies can distinguish, but at some cost:
"obj.name" returns a function proxy with a promise as target (no big
deal :-p ). This sends neither GET nor POST but waits for the end of the
"event loop turn". If the proxy function has been called send a POST (as
many times as the function proxy has been called with respective
arguments each time). If the event loop turn is over and the function
has not been called, then perform a GET and the (function proxy) promise
stops being callable.
The point is that at the end of the "event loop turn", you know what the
intention of the author is but you haven't started fulfilling promises,
so it may be worth waiting to know whether to do a GET or a POST.

It comes with the cost of waiting for the end of "event loop turn" which
may never come... but promises won't be fulfilled anyway if it doesn't
come, so whether you did a GET, a POST or nothing changes from a network
perspective, but does not from a JavaScript program perspective.
And since the idea is fresh, I may be ignoring some program correctness
cost.

Cheers,

David
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20111129/d5a125b3/attachment-0001.html>


More information about the es-discuss mailing list