Subject: Re: Harmony - proxies | asynchronous
Bradley Meck
bradley.meck at gmail.com
Sat Sep 3 20:50:49 PDT 2011
While I tend to use vocabulary more loosely than those who associate a
model or structure to a programming language I am sorry for any
confusion.
Actors : http://en.wikipedia.org/wiki/Actor_model
>From my standpoint the idea of event emitters using callbacks the
callbacks are being treated as actors. On a more casual level actors
could relate to deferreds / promises / monads / etc. as you wish to
call them if you insist on using them as the event's reactor being
forcibly the object that has the callbacks associated with them.
Perhaps message based programming would have been a better term,
however I needed to convey a sense of shared state. In this case the
closured variables that a function can concurrently mutate (not in
direct parallel due to single threaded nature).
Monads : http://en.wikipedia.org/wiki/Monad_(functional_programming)
>From this article (simplest example is the state monad) we can see
adding dynamic information to a set of calculations. How is this
drastically different from a closured variable and a callback (dynamic
typing aside)? Perhaps I am confused about this, but it was my
understanding that monads need not be their own object aside from the
invoker and that they represent a calculation tied to state
information. At least that is how I have used them in the past.
Strict Mode Error:
Reduced example - http://jsfiddle.net/zrX5B/
This is exceedingly rare in need but an example of if you want to
support streamline.js and you have a C++ module that uses the event
loop, you may need to detect random junk that gets treated as async or
blocks, and if it gets blocked you may need to act accordingly.
Node / DOM Prior Art:
Just because it is done before does not mean it is encouraged, loved,
or even sane. Almost every time someone saves a NodeList in the DOM
the first time, they end up searching for WTF is going on. The same is
true about cacheing Node buffers related to streaming reads from the
file system.
Preemption / Asynchronous point:
This relates to the idea of proxy asynchronous behavior not blocking
code execution. By that I mean that they lack coroutine like
cooperation (via a yield [JS yield behaves a bit different than the
definition used here] / callback / etc.) to determine when it is safe
to continue the current flow of control for our program. I will refer
to blocking asynchronous function proxies as proxies that involve
cooperative measures. An example of these would be best:
Assume a Proxy of type ASYNC will do a remote HTTP request whenever a
property is accessed / set (lets assume standard REST CRUD). This
could be used for some nice database persistence without much effort.
Given an example of a service helper function:
function prepare(service, data) {
service.data = data;
}
prepare(service1, 'hello world!');
console.log('data loaded!');
If the service is not an ASYNC we know that execution will block as
per normal and order will be preserved.
If the service is an ASYNC and Asyncchronous Proxies block execution
(until cooperation) we also know order will be preserved and the event
loop will be blocked during this.
If one service is ASYNC and Async Proxies __do not block execution__
we have a problem:
* we do not know exactly when prepare will be done (in case we need
cleanup on a failure, particularly brutal if we want to fail if a
certain timeout is set, but this actually ends up succeeding)
* the console.log may fire before the data is loaded
* even worse if we are setting variables to determine state
Ok, so lets step back and take a closer look at blocking execution for
asynchronous function proxies.
What does this get us:
* Be able to treat an asynchronous function (the handler of the
proxy) as if it were synchronous. Very good.
* Blocks the event loop at potentially unforeseen times. Very bad.
You cannot allow this in some time critical paths (protocols that
require time assurances or abort callbacks on timeout instead of
waiting 180s for TCP timeout, etc).
Finally I get to a point of discussion on everyone wanting everything
to look pretty, even if it causes these problems, and means everyone
must follow the convention.
function DBEventEmitter(adaptor) {
var self = this;
adaptor.connectionString = 'x';
//have to do this on nexttick, adaptor may be synchronous (in memory)
process.nextTick(function() {
adaptor.init();
});
}
Now when we move this to a land with Async Proxies, I have no doubt we
will see the following:
function DBEventEmitter(adaptor) {
adaptor.connectionString = 'x';
}
Looks nicer, but if we need to register events onto the
DBEventEmitter, it must be done ... prior to the constructor? Ok, well
we will just do a nexttick to allow that, even though we are
guaranteed init will succeed by the time the function returns. We
could get rid of event registration all together, but for that would
mean wrapping all async adaptors in async proxies, that is a lot more
trouble than just using a simple function invocation and callback.
Even with helpers and enumeration of properties, this could become
difficult to automate without adding a separate config definition to
see what properties should be considered async in order to provide
cooperative concurrency (actually seems to remind me of WSDL where you
end up making a type for promises).
Sorry if I sound aggressive, but I have strict opinions about explicit
behavior rather than potentially surprising behavior for code
aesthetics. If a different invocation syntax was required so that one
could tell that something may take time due to being async I would
have little issue. I merely do not see much gain in combining two
drastically different execution types into a single syntax.
More information about the es-discuss
mailing list