Node has shared memory between actors, having multiple async code
flows executed on shared memory that appear to be sync by design is
very hard to do. This leads to implementation specific behavior unless
we standardize edit resolution. Most people who complain about nested
callbacks generally forget that you can abstract away event delegation
to objects and objects can manage multiple states. Also, if you are
nesting many callbacks, you should probably try to split up the
functionality to logical pieces, our code base of 20k+ lines of Node
rarely if ever sees more than 3 nested functions (including the
original invoker).

While memory resolution is possible and able to be standardized it can
prove difficult when working with Native object where state of memory
may be cached in C/C++/etc. Web workers have provided a nice
share-nothing abstraction that is probably more suitable than
overhauling the fact that closures can share the same memory. On top
of this, critical expectations of sync behavior would require any
memory access that could affect the shared memory be either locked and
prevented or rolled back at a later time.

The DOM's live NodeLists are a good example of shared memory causing
issues in this area, proposing all proxies be allowed to do this is
would require the same care that every time we deal with a live
NodeList requires. Even worse, libraries must support this, similar to
how a few libraries that break when a script in strict mode invokes
them but unlike frowned upon features, we are talking about every
feature that a proxy has would have to be guarded for this.

Monads through callbacks instead of hiding async behavior through
proxies is a better idea not just because of the complex compilation
changes needed to support this, but also because a user of an API can
expect for something to have an unknown return time with callbacks.
Explicit behavior will always be more appropriate than "magic" async
behavior appearing synchronous with shared memory is what leads to
hard to debug race conditions. Semaphores will become needed to lock
resources that merely *may* be affected by something that *may* be
occuring but is not guaranteed to be. Having the compiler do this
would lead to nightmares. Not sharing memory between concurrent flows
of control and not splitting flows of control that may have preemption
is much more sane.

If you wish to discover more about this I would suggest looking at the
solutions in shared memory systems for C++, Node, and Java. C++ and
Java will be using semaphores to cage potential race conditions, while
Node generally can get away with counters (we have seen cases where
when we have to use workers we rely on semaphores so I would suggest
looking at process race conditions in these as well).

Cheers,
Bradley
_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to