Spray I - The Actor Model

17 August 2015

Introduction

While trying to get the implementation of a rudimentary Regex engine working, I've been focusing my learning almost exclusively on building a compiler, neglecting the process of improving my Scala and Functional Programming ability. In order to bring the two together, I've decided to build each component I create into a web application, thus learning more about the frameworks and tools available to Scala developers, more about the algorithms and patterns available to functional programmers and building my knowledge of developing on the JVM.

Introducing Spray

I did the most reasonable thing one might do when trying to figure out where to start building a web application in Scala, I Googled it and ended up on Stack Overflow. There were a few different frameworks that caught my attention, but it seems today, with languages like Erlang and Elixir and frameworks like Microsoft Orleans, that the Actor Pattern is the new hotness. Therefore I decided to use the Actor Pattern based framework for building web applications in Scala called Spray. Spray is based on Akka, an Actor Pattern framework for the JVM.

The Actor Pattern

The Actor Pattern is a pattern of concurrent software development that has been growing in popularity over the past few years. It's actually, however, a very old pattern, Wikipedia dates it at 1973. The Actor pattern aims to help developers get a better handle on concurrent application design by abstracting away some of the complexity of dealing with concurrency. You can think of an actor as a simple OOP object, with a conceptual mailbox. Actors interact with each other and the world through sending and receiving messages to and from those mailboxes.

An actor in Akka is a class that extends the Actor trait. The only thing on this trait that needs to be implemented by the actor is the receive partial function. This function is executed in a single-threaded manner and can handle different messages one at a time. This greatly simplifies concurrent programming, as concurrency is achieved through the higher-level composition of these actors. The decision of what messages to process is, naturally, handled through Scala pattern matching.

Let's look at an actor that I created to handle receiving a Regex pattern in it's mailbox, parsing it and sending the result back to the sender's mailbox.

There's a lot of new concepts in there, so let's go through them one by one:

Partial Functions

So we have our actor class RegexWorkerActor and we know it's an actor because it extends the Actor trait, which is like an abstract base class in .NET or Java.

All seems pretty normal here, and the actor trait has a single method on it, called receive. We start to implement receive and then... what? Why is there a case statement without a match? So far, on this blog, we've seen pattern matching and barely scratched the surface of it's awesomeness. However, every time we've seen pattern matching, it's been in the form of:

With a leading match keyword. So what is going on here?

After a bit of Googling, and swallowing my pride and asking on the Akka/Akka Gitter channel, I discovered that this is something called a partial function. If you want to learn more about partial functions, then I'd suggest this great post.

As a brief introduction, partial functions are functions that explicitly define what inputs they accept. PartialFunction is a Scala trait that contains two method, apply which is a function that performs the actual logic of the partial function and isDefinedAt which will return true or false depending on whether the function accepts that input.

Looking at our receive partial function, we are now placed to understand the use of the case keyword without the match keyword. For partial functions, Scala provides us some syntatic sugar, using the case keyword to implicitly set up the apply and isDefinedAt functions. It's this syntatic sugar that we're using here.

The Akka receive function is defined as a PartialFunction[Any, Unit], and our implementation of receive matches on a String value only. Therefore our apply function would be the anonymous body of our String match and our isDefinedAt will only return true for a parameter of type String. If one was to send a message to this actor that was not in the form of a String, an exception would be thrown.

Ask and Tell

The next interesting piece of new syntax is the ! operator. As mentioned above, actors in Akka interact through their mailboxes. To perform this interaction, an actor can ask or tell a message into an Actor's mailbox. The ! operator performs a tell operation, and sends a method to an actor without expecting a response.

In the example above, we tell the sender the result of the Regex parse operation. An Akka actor knows who sent the message through the sender() function on the Actor trait.

We'll look at the other operation, ask, in the next blog post.

Case Classes

In the RegexWorkerActor object, we have a RegexResponse case class. A case class can be used for functional decomposition as part of pattern matching. (Note: previous versions of this blog post incorrectly stated that Case Classes contained data but not methods. This was incorrect. While this was the way I was using case classes, this is not a restriction in Scala)

You can read more about case classes here.

Learning More About Akka

We'll be covering a lot more about Akka in future blog posts, however, if you find your appetite whetted and need to know more, the first half of this YouTube video is particularly helpful:

Conclusion

That's a lot for a single blog post, and we've got a lot more to cover before we can have a working web application. Stay tuned, and next time we'll talk about how to use this actor with Spray.

Tags: Scala | Spray.IO | Akka | Actor Model
Tweet