This is another topic which comes up from time to time on the mailing list: typed actors are “nice”, but some things work differently or not at all, so what exactly are they good for?
As a little historical side-note, typed actors in Akka 1.x were implemented using runtime byte-code generation by the AspectWerkz library, which is no longer actively maintained. Thus, Viktor re-wrote them based on JDK proxies, while integrating them more smoothly with the rest of Akka. In version 2.0, typed actors are free of external dependencies and part of the core module “akka-actor”. They can send and receive messages like normal actors, be supervised by normal actors and supervise normal actors, they can intercept life-cycle monitoring messages and take part in the EventStream, but all of this does not come quite as naturally as for the normal untyped actors. The reason is that typed actors do not ideally model what actors are: entities which process an incoming stream of messages with their behavior, changing their state in response and generating other messages. The simplicity of this model is what enables perfect encapsulation in a truly object-oriented way and it enables the location transparency and fault tolerance of actor systems.
But typed actors do have their place, as hybrids between POJO and Actor: exactly at the touching point where actor systems meet non-actor code. Communication between actors means placing message objects into the recipient’s mailbox, which is not easily done if the receiver shall be a plain Java object. A typed actor is a normal actor wrapped in a given interface, responding to method calls instead of message sends.
A Simple Example
The Service is represented by a simplified interface, which is implemented by an inconspicuous class ServiceImpl. The vigilant reader will have noticed that the special magic enters on line 18 by way of TypedActor.context, that returns the ActorContext of the untyped actor which will be wrapping this implementation. The next line then demonstrates the creation of the child actor which will be servicing the requests. Notice how the asynchronous nature of actor communication is retained by returning a Future for sending the (eventual) reply back to the requesting party.
The only noteworthy action with respect to typed actors is shown on lines 38ff, where the typed actor is instantiated. Declaring a normal actor and handling Future callbacks is assumed prerequisite knowledge for this post.
What else can you do?
What you just witnessed is the basic principle of wrapping a function implemented by an actor system into an interface which can be consumed by “normal” non-actor code. This should be enough to get going, but you will probably at some point want to learn about the various additional traits: Supervisor, Receiver (for receiving normal messages), life-cycle callbacks PreStart, PreRestart, PostRestart and PostStop.
What should you NOT do?
Most importantly, use them sparingly: untyped actors make the actor model more explicit, which will benefit your application design. That said, in those cases where a typed actor is preferable (for example as shown above), only declare methods which return either Unit (i.e. «void») or a Future. All other possibilities lead to blocking behavior when sending an invocation to the actor, and parking one thread only to wake up another is not a good idea. Also, making the reply (if any) asynchronous enables you to distribute your application across multiple network nodes without running into the RPC troubles.
And above all: never send a «this» reference to anybody, which includes arguments to method invocations on different objects. If you for example register the typed actor implementation for a callback, that callback will be executed concurrently to the typed actor itself and in a different context, leading to all those pesky locking problems which you wanted to rid yourself of by using Akka. If you must send around something which represents the typed actor, always use «TypedActor.self».