Today’s post is a guest post by Bill la Forge, from the JActor project. The original post is here. I asked Bill to expand on something he’d written earlier, because I was struck by the simple yet deep truth that sometimes one change in your code has a cascading effect on other parts of the code – sometimes for good, and sometimes not. And when it’s for good, and unexpected, it’s delightful.
If you’d like to have any of your project blog entries republished on the SF blog, please let me know.
–Rich
Release 2.0.0 of JActor will be characterized as providing classifications of requests: constrained and initialization. Constrained requests can be invoked by the Internals.call or Actor.acceptCall methods, while “unconstrained” requests must be invoked by the Internals.send, Internals.sendEvent or Actor.acceptRequest methods. The big advantage of initialization and constrained requests (and events) being that we are free from having to deal with callbacks to handle responses. The call and acceptCall methods directly return the results (the results from sending an event being ignored).
There are two basic types of constrained request: synchronous (new) and concurrent. Synchronous requests can only be passed using a call or acceptCall method when the sender and receiver use the same mailbox; concurrent requests must be thread safe and can only access concurrent data structures.
Initialization requests (new) can only be passed during the initialization phase of an actor, and the initialization phase ends when an actor receives a “non-initialization” request. Initialization requests are processed on the same thread as the sender under the assumption that initialization requests are sent one-at-a-time, so thread safety is not an issue.
The result of classifying requests as constrained or initialization is that we can then classify more requests as constrained or initialization. This is a cascading effect that, in many cases, frees us from the mess inherent in using anonymous callback classes. It is also faster, as GC no longer needs to collect all those callback instances.
I have seen such cascading effects a number of times. They are always delightful, as the code ends up being ever so much simpler. Such cascades occur when you can identify constraints that simplify processing. A rich API that supports a number of constraints makes simple things fast and easy to use. This contrasts nicely with API that are rich in features, i.e. unconstrained.
Bill la Forge, JActor project