A programming model with multiple flows of control, regardless of the underlying implementation requires some mechanism for mitigating race conditions. Most thread-like systems implement synchronization primitives such a mutexes, semaphores and the like. It is an explicit design goal of Corona to provide a programming model that does not require use of these constructs: threads are hard.
That said, there must be some model for allowing control flows to interact with and reason about global state in the presence of blocking API calls. Corona's attempt to address this is the following set of runtime features
- Support for futures: When invoking an function call that needs to block to compute its return value, rather than blocking the process immediately, the function can return a Future object immediately, without blocking. This Future represents a holder for the future return value of the function. Only when this object is interrogated does the process block. This allows developers to implement atomic codepaths that span multiple nominally blocking functions.
- Toggling blocking/non-blocking mode: A set of primitives will be provided to ensure that the runtime does not block. These can be used to implement critical sections. An exception will be thrown when any system call is invoked that would otherwise block the currently executing control flow.
- Purely asynchronous programming requires developers to maintain the application state machine in two places: the stack, and state explicitly maintained and passed around to callbacks.
- In practice, purely asynchronous programming can necessitate deeply nested callback structures. Such a control flow is more concisely represented in a linear sequence of blocking calls.
- Correlating callbacks to the codepath that created them is often difficult. The canonical example for this is throwing an exception inside an event handler -- who "owns" the event handler and where did it come from?