Hello World in Akka (Part I)

Today we are going on a different matter. Since the reactive programming course is currently being given in Coursera, we are taking the first steps to start working with Akka.

Akka is a toolkit developed by the Typesafe ecosystem. It allows the implementation of reactive systems on an actor-based model. There are two versions of Akka, one for Java and one for Scala. We will focus, obviously, on the second.

What’s an actor?

An actor in an entity to which messages can be sent. The actor will react to the received messages by performing an action. Besides, it has two main characteristics:

  • The inside of the actor can’t be accessed from outside. The interaction with the actor can only be achieved by sending messages to it.
  • Messages that arrive to the actor will be processed one at a time.

To create an actor in Akka – please make an extra comprehension effort – the only thing that is required is extending the trait Actor.

If we want the actor to be fully defined, its behaviour needs to be specified. In order to do so, the receive method of the actor needs to be implemented. This method will define the reaction of the actor to the different messages that it might receive.

But before going on with actors, tool time!

timallen

Tool time: Partial functions

Partial functions are functions that are only defined for a limited set of arguments. From a mathematical point of view, we could say that its domain is bounded. This concept may become clearer with a simple example:

def getCountry: PartialFunction[String, String] = {
  case "Madrid" => "Spain"
  case "Paris" => "France"
  case "Roma" => "Italy"
}

In this case, the getCountry function will return the country only for the capital cities defined in the partial function. If any other capital city is used as input to this function, it will throw a MatchError.

getCountry("Madrid") //returns "Spain";
getCountry("Berlin") //throws MatchError

Moreover, partial functions have a method called isDefinedAt, which allows us to know if a certain input parameter is considered in its body. In our example:

getCountry.isDefinedAt("Madrid") //returns true
getCountry.isDefinedAt("Berlin") //returns false

Another important trick is that partial functions can be combined to create a new one. To do so, orElse method is used.

def getCountryEurope: PartialFunction[String, String] = {
  case "Madrid" => "Spain"
  case "Paris" => "France"
  case "Roma" => "Italy"
}

def getCountryAmerica: PartialFunction[String, String] = {
  case "Brasilia" => "Brazil"
  case "Buenos Aires" => "Argentina"
}

def getCountry =
  getCountryEurope orElse getCountryAmerica

getCountry.isDefinedAt("Madrid") //returns true
getCountry.isDefinedAt("Brasilia") //returns true

To end up with the PartialFunction masterclass, it is important to know the method applyOrElse, with which we can evaluate a partial function with an input value but also define an auxiliary function to use in case the input value does not belong to the domain. Sorry, what? Again, an example might save us:

def unhandled(capital: String) = s"$capital is not defined"
getCountry.applyOrElse("Foo", unhandled) //Foo is not defined

Hello World Actor

Good! Now we know what partial functions are, we can implement the receive method of the actor, which will define the actor’s behaviour. That receive method, as you all might have guessed, is a partial function actually.

type Receive = PartialFunction[Any, Unit]

def receive: Receive

This partial function expects any type as input parameter and returns Unit. Therefore, thanks to the argument type Any, anything can be sent as a message to the actor: a string, an integer, an object…

def receive {
  case num: Int => println(s"Num $num received")
  case words: String => println(s"String $words received")
  case _ => println("I've received other thing")
}

In addition, we must know that when a message arrives to an actor, at first the partial function defined at the receive method tries to be applied and, in case the message is not defined in the domain, the unhandled method is executed:

def unhandled(msg: Any): Unit

By default, this method will print the unhandled messages in a log. This way, if a message cannot be handled by receive method, instead of causing a MatchError and blowing up our program, a debug message will be printed in Akka’s log. Using our high-level knowledge in partial functions, we can guess that the behaviour of an actor for a given message called msg will be defined as follows:

receive.applyOrElse(msg, unhandled)

All that remains is to define the actor that, in our case, no matter what the received message is, will print a lovely and passionate Hello World:

class HelloWorldActor extends Actor {

  def receive {
    case _ => println("Hello World!")
  }
}

Voila! The next post will teach us how we can use this actor and put it into operation.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s