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.
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:
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
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
isDefinedAt functions. It's this syntatic sugar that we're using here.
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.
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:
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.