Lately I’ve been doing a lot of experimenting and playing with Scala and Akka. I’ve been building a MUD to give me a goal as I learn the language, the framework, and the intricacies involved.
So far I’ve been focused mostly on syntax and learning what idiomatic Scala looks like, how to create and use Akka actors, and so on. It wasn’t until the other night that I started thinking about design and philosophy. This mini-revelation came about when I spent hours trying to find a way to get the actual type from underneath an ActorRef.
I was using context.actorOf() to create actors, as one should with Akka 2.0. So I might be creating and starting actors for rooms, monsters, or living room tables – anything that I thought might be instructive to mess around with. This is when I noticed that once you create an ActorRef by adding your actor to the actor system (either via system.actorOf or context.actorOf) you can’t get at the actual class underneath. All you can do is interact with it like an actor-shaped black box by sending and receiving messages.
In other words, let’s say I’ve got a class called Zombie that is an actor that I’ve added to the actor system. The Zombie has properties like name, eatingSpeed, and percentLivingTissueRemaining. With regular Scala actors, I would’ve been able to mix and match classic OOP-style programming with actor-style programming:
println(tehZombie.name) tehZombie.percentLivingTissueRemaining = 12 tehZombie ! FeedUpon(randomVictim)
At first this might look nice and appealing, but there’s something insidious happening here. First, our code has access to the internal state of tehZombie for both reading and writing. Secondly, we can send actor-style messages to tehZombie. Back during my first attempt at a MUD using regular Scala actors, I regularly abused this capacity – reading public fields from instances of actors all the while sending them messages.
One main purpose of an actor system is to take the complexity away of multi-threaded access to shared state and business logic. If we have one actor able to access another actor using standard OOP-style member-access patterns, we’ve basically ruined all of the advantages we’re getting from the actor system to begin with because access to public state on an object is not inherently thread-safe.
If we change internal state on an Akka actor in response to a message, we are guaranteed that such a state change is thread-safe. Not only is it thread-safe, it’s single-threaded because the actor’s inbox is being processed by that actor’s thread (or thread pool) and no one else.
So what does this mean? It means that, within the context of an actor system, public state and OOP-style member access is BAD.
Unfortunately, what this means for my MUD is that I’ve got some refactoring to do because I noticed that I’ve been cheating and I passed around a reference to this to another actor – which gave that actor “unsafe” access to public members of my class. What I really should be doing is making sure that nothing on my actors is exposed publicly and I should be aiming for a message pure environment where everything works as though actors are black boxes that just receive messages, do what they need to do, and send back out messages to other actors within the system.
Akka 2.0 enforces an awful lot of this by suppressing access to this from other actors (I cheated… bad, bad, Kevin). Hopefully within a few days (after the Giants win the Super Bowl) I will have some refactoring checked into the Github repo that hopefully has a fully functioning system that is clean, message pure, and exposes no unsafe members.
Wish me luck 🙂