I've been using Akka and Scala for about a month and I'm somewhat bothered by replacing explicit interfaces with messages. Consider the following simple Akka Actor:
case class DoMyHomework()
class Parent extends Actor {
def receive = {
case d: DoMyHomework => // do nothing
}
}
Actor or non-actor code that sends this actor a DoMyHomework message like this:
ActorRef parent = ...
parent.ask(DoMyHomework)
Has no idea what the outcome will be. What's the type of the answer? Will I ever get an answer? Can I get an exception? And so on.
The fix seems to be to document the case class... but what if some other actor also receives that same case class. Then the documentation should for receiving that message should be in the actor itself.
In an effort to clean this up a little I thought of doing the following:
trait SomeoneSmarter {
def wouldYouDoMyHomework: Future[Boolean]
}
class Parent extends Actor with SomeoneSmarter {
case class DoMyHomework()
def wouldYouDoMyHomework = {
(self ? DoMyHomework()).mapTo(Boolean)
}
def receive = {
case d: DoMyHomework =>
// TODO: If I'm busy schedule a false "No way" reply for a few seconds from now.
// Just to keep their hopes up for a while. Otherwise, say sure right away.
}
}
So, I chatted with colleagues about this and one of the reactions was "you're not being true to the actor model."
First, I would really appreciate some guidance from folks that have been using Actors for a longer time. Do all the messages become unwieldy? Do you end up hiding message-passing behind interfaces?
The actors I'm proposing still have the option of sending messages among themselves, subscribing to event streams, all the stuff you expect from Akka. And the interface gives you a time-tested way of knowing what you're talking to. And it helps when coding in IDEs, and so on. And why should the user of an actor need to know it's an actor (unless it's also an actor and is very tightly coupled with it)?
The other reaction I got was "it looks like you want a TypedActor". But after reading about TypedActor I'm not convinced. Certainly TypedActor saves me the trouble of creating those internal messages. But, at least from the code sample at http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html I get the impression that the TypedActor is meant only to work as a proxy around a block of code you want to encapsulate, or make thread-safe, or simply not call directly from your current thread. And what you code is just the implementation and interface. You don't mess with the actor itself (the proxy) - e.g. if you want your implementation to do periodic work or subscribe to an event stream, or do anything else unrelated to the interface.
I've also read http://letitcrash.com/post/19074284309/when-to-use-typedactors and didn't find that example more illuminating. I'm probably just not grokking TypedActor (not that I claim to have really understood Actors yet).
thanks in advance for help.
Pino
Disclaimer: I'm not an Akka/Actors expert. I've been working with Actors and Akka about 18 months and I'm still trying to wrap my head around certain concepts especially when not to use Akka.
For the particular and narrow case that you want to know the return type of an Akka future, yes, you should use a TypedActor. The few times I've used TypedActors they were used to provide an API to a module that fell outside the Actor system. That is, I've built a system on top of Akka that did most of its work inside an Akka network but had one or two modules outside of the Akka network that required access to the features provided by the Akka network. The most notable was a Scalatra frontend that called into the Akka network and did some work on the values returned by the Akka network before responding to its client. The TypedActor, however, was really just a frontend to the Akka network. I look at using a TypedActor as an API frontend to external (external to the Akka network) modules as another separation of concerns.
In general, I agree with those that are telling you that "you're not being true to the actor model" in trying to coerce a view of its return types. In its purest form, and the way I've had the most success, the Actor model is implemented using fire and forget semantics. The messages do not get unwieldy and in many cases they've helped organize my code and define work boundaries. It does help to put them in their own package.
Were I to implement the feature you've described it would look like the following:
Keep in mind the way I've written wouldYouDoMyHomework, it will block while waiting for an answer. There are clever ways to do this asynchronously however. See http://doc.akka.io/docs/akka/2.0.3/scala/futures.html for more information.
Also, keep in mind that once your message is inside the Akka network you can do all of the cool scaling and remoting stuff and the user of your TypedActor API never has to know.
Doing this does add some complexity in large projects but if you consider it as seperating the responsibility of providing an API to external modules and maybe even move that responsibility to another package it's very easy to manage.
Good question. I can't wait to hear answers from the more experienced Akka developers.