Modern Functional Programming and Actors With Scala and Akka

Aaron Kosmatin Computer Science Department San Jose State University San Jose, CA 95192 707-508-9143 [email protected]

Abstract sons for this. Functional programming languages place a strong emphasis on minimization of side ef- For many years, functional programming has had fects, and immutable states. Functional program- an academic presence in computer science, but ming is an expansion of lambda calculus. The has been poorly represented in popular languages. idea of functional programming is that the pro- Functional programming has been making a resur- gram executes as a series of mathematical func- gence lately. With 8, Oracle has introduced tion evaluations[2]. From its mathematical nature, lambda functions, an essential part of functional every function call that has the same arguments programming, to Java. Much of the resurgent in- should produce the same return statement. terest in functional programming originates with Martin Odersky, designer of Scala and Co-founder of Typesafe. The of concurrent programming The emphasis on reduction of side effects has pre-dates Scala, with implementations in languages hurt the adoption of functional languages in the such as Erlang, but has been an underutilized industry, many programs require some form of side model. The Actor Model is well adapted to multi- effect. Side effects include any modification of a core and multi-machine programming. The Actor state, such as modifying a variable, printing to the Model has regained interest recently due to the console and writing to files. As well, for many pro- work of Jonas Bon´er,developer of the Akka Ac- grammers, it is easier to conceptualize problems by tor library for Java and Scala and Co-founder of modifying states. Typesafe. Scala and Akka actors provide developers with well developed tools for parallel and distributed computing. Due to the tools available with the While there are drawbacks to functional pro- Typesafe platform, Scala and Actors have become gramming, there are two important advantages. a core part of the technology stack at companies First, functional code tends to be easier to read like Twitter, LinkedIn, and Netflix. and maintain between programmers. By its na- ture, functional programming has few mutable vari- ables. It is not required for a programmer to track 1 Functional Programming how a variable is changing through the execution of the code. Second, with its emphasis on immutabil- Functional programming has not seen wide use in ity, functional programming tends to be much more the programming industry. There are several rea- parallelizable.

1 1 o b j e c t VarValDeclarations { 1 o b j e c t firstClassFunctions { 2 vara=1 2 d e f f(x: Int) =x+ 2; 3 v a lb=2 3 p r i n t l n(Array(1,2,3).map(f)) 4 v a l c:Int=3 4 } 5 d e f aFunction(value:Int):Int = { 6 value Output: 7 } 8 d e f bFunction(value:Any) = { Array(3, 4, 5) 9 value 10 } 11 } Figure 2: First class functions in Scala

Figure 1: Variable and Value declarations Scala collections. By default the members of a col- lection are immutable, unless a mutable collection 2 Scala is imported by the programmer. A last thing to notice in figure 1 is that the Traditionally, Object oriented programming has functions do not have an explicit return statement. been a subset of procedural languages, with lan- Scala does support the return keyword, but will de- guages like C++ and Java. In 2003, Martin fault to returning the last line of a function block. Odersky developed Scala for his programming lan- This makes sense given Scala’s functional influence. guage class at Ecole´ Polytechnique F´ed´erale de Function’s with no return, or void functions, are Lausanne[1]. He wanted to show that object ori- used to create side effects, but since functional lan- ented programming was compatible with functional guages try to eliminate side effects, every function programming. should have a return value. Strictly speaking, Scala is not a functional pro- Figure 2 shows how functions can be used as first gramming language, nor is it a procedural lan- class objects in Scala. This is a standard feature of guage. Scala fully supports both forms of program- functional programming, where a functions can be ming. Scala is built on top of the JVM, and com- used in the same manner as other types. In this piles to Java bytecode. As such, Scala is compatible example, the function f is used as an argument to with Java libraries, and Scala libraries are compat- the map function[3]. ible with Java. Scala addresses one of the limiting As can be seen from figure 3, Scala and Java factors of previous functional languages, in that it are similar. One important difference is that unlike allows the programmer to use procedural program- Java, Scala supports the Singleton Design Pattern ming when required. at the language level. In Scala, an object is a single- ton. Since Scala is object oriented, it also supports 2.1 Scala Language Basics classes and an object hierarchy like Java’s. Scala has a philosophy of offloading much of the 2.2 For Yield Condition/Map Filter typing to the compiler. Like Java, Scala is a strongly typed language, but the type is usually Scala supports functional constructs, such as maps. inferred by the compiler at compile time. Lines 3 In figures 4, 5 and 6 show examples of Scala’s for- and 4 of figure 1 show the declaration of two inte- yield syntax. In figure 4, maps are used to generate gers. On line 3, the type is inferred by the compiler, a cartesian product. In figure 5, a for-yield state- and on line 4, the type is explicitly set by the pro- ment is used. At compilation, the code in figure 5 grammer. is converted into code similar to figure 4, however, Scala also supports variables and values. Vari- depending on the situation, one may be more read- ables work as expected from other languages. Val- able than the other[4]. In figure 6, a condition is ues are the immutable variant of variables. Scala, added to the for statement, removing symmetric in general, prefers immutable objects. An exam- results. A similar condition can be applied to the ple of Scala’s preference for immutability is in the map syntax.

2 Listing 1: Java Hello World Listing 2: Scala Hello World

1 p u b l i c class HelloJava { 1 o b j e c t HelloScala { 2 public static void main(String[] 2 d e f main(args: Array[String]) { a r g s ) { 3 p r i n t l n(”Hello Scala”) 3 System.out.println(”Hello Java”); 4 } 4 } 5 } 5 }

Figure 3: Hello Worlds in Scala and Java

Listing 3: Sequential Loop Execution Listing 4: Parallel Loop Execution

1 o b j e c t ParallelExample extends App{ 1 o b j e c t ParallelExample extends App{ 2 v a l integers=1 until5 2 v a l integers=1 until5 3 v a l timesTable=for(integer1 <− 3 v a l timesTable=for(integer1 <− i n t e g e r s ) yield { integers .par) yield { 4 f o r(integer2 <− i n t e g e r s ) yield { 4 f o r(integer2 <− i n t e g e r s ) yield { 5 i n t e g e r 1 ∗ i n t e g e r 2 5 i n t e g e r 1 ∗ i n t e g e r 2 6 } 6 } 7 } 7 } 8 timesTable. foreach(println( )) 8 timesTable. foreach(println( )) 9 } 9 }

Output: Output:

Vector(1, 2, 3, 4) Vector(1, 2, 3, 4) Vector(2, 4, 6, 8) Vector(2, 4, 6, 8) Vector(3, 6, 9, 12) Vector(4, 8, 12, 16) Vector(4, 8, 12, 16) Vector(3, 6, 9, 12) Figure 7: Sequential and parallel execution of loop statements.

1 o b j e c t CartesianProduct extends App { 1 o b j e c t CartesianProduct extends App { 2 v a l points = 0 until5 2 v a l points = 0 until5 3 v a l cartessianProduct=for {x<−p o i n t s 3 v a l cartessianProduct = points.flatMap(x 4 y<−p o i n t s } y i e l d { => points .map(y= > ( x , y ) ) ) 5 ( x , y ) 4 p r i n t l n(cartessianProduct) 6 } 5 } 7 p r i n t l n(cartessianProduct) 8 } Output: Output: Vector((0,0), (0,1)...(6,6)) Vector((0,0), (0,1)...(6,6))

Figure 4: Map Syntax Figure 5: For Yield Syntax

3 Listing 5: Parallel Loop Execution 1 o b j e c t ParallelExample extends App { 1 2 v a l integers = 1 until5 import scala.collection.parallel.ParSeq 2 3 v a l timesTable = for (integer1 <− i n t e g e r s ) yield { 3 o b j e c t ParallelExample extends App{ 4 4 f o r { i n t e g e r 2 <− i n t e g e r s v a l integers=ParSeq(1,2,3,4) 5 5 i f (integer2 <= i n t e g e r 1 ) v a l timesTable=for(integer1 <− i n t e g e r s ) 6 } y i e l d { y i e l d { 6 7 i n t e g e r 1 ∗ i n t e g e r 2 f o r(integer2 <− i n t e g e r s ) yield { 7 8 } i n t e g e r 1 ∗ i n t e g e r 2 8 9 } } 9 10 timesTable. foreach(println( )) } 10 11 } timesTable. foreach(println( )) 11 } Output: Output: Vector(1) ParArray(1, 2, 3, 4) Vector(2, 4) ParArray(4, 8, 12, 16) Vector(3, 6, 9) ParArray(3, 6, 9, 12) Vector(4, 8, 12, 16) ParArray(2, 4, 6, 8)

Figure 6: Conditional For Yield Figure 8: Parallel Collections

2.3 Parallel Execution of Collections order of rows is not deterministic. In this exam- The first example of parallel computation methods ple, the order of the columns has been preserved, that exist in Scala, but not Java, can be seen in but this can not be relied on. Parallel collections figure 7. In this case, the .par operator is added provide a simple, powerful data type for processing on line 3. The code on the left executes sequen- large collections where the order of the collection is tially, the code on the right is executed in paral- not important. lel. By adding the .par operator, Scala knows to treat that collection as parallel. While executing, 2.4 Pattern Matching it will determine how many threads are available, create the threads, parse parts of the collection to Another important feature of Scala is pattern each thread and then join the results. It should matching. Pattern matching is used in several ways be noted that the resulting collection timesTable in Scala. In figure 9, several examples of pattern is no longer deterministic and may change between matching can be seen. The first example is pattern different executions of the code. This is why the matching on value, the second is pattern matching third and fourth lines of the output have reversed on type, and the third is using the Option data order from the original output. This parallelization type. Option is a wrapper for optional values. It of mappings can be done in other languages, but its is used for passing optional data. Each example execution is much simpler in Scala. of pattern matching can be further developed to In fact, Scala supports a large range of collec- provide more complex behaviours. tion implementations. Some common ones are Seq, which is similar to an Array in Java, List, which 2.5 Concurrent Execution of Fu- is similar to an ArrayList in Java, and Stream, a tures collection type that was added to Java 8 in which the individual members have lazy evaluation. For Futures are another method of parallel execution most collections, Scala also supports a parallel ver- in Scala. Futures generate a new thread, where the sion. In figure 8, the code has been changed to use future is evaluated. While the future is evaluat- a parallel collection instead of a sequential collec- ing, the main thread of execution is still process- tion. Similar to the previous parallel example, the ing. When the future completes, it return to the

4 1 o b j e c t PatternMatching extends App { 1 import scala.concurrent. 2 d e f matchValue(x: Int): String = x match 2 import scala.concurrent.duration. { 3 import scala .concurrent.ExecutionContext 3 c a s e1= > ”one” 4 .Implicits.global 4 c a s e2= > ”two” 5 import scala.util. { Failure , Success } 5 c a s e => ”many” 6 6 } 7 o b j e c t FuturesExample extends App{ 7 p r i n t l n(matchValue(3)) 8 v a l a:Future[String] = future { 8 9 Thread sleep 1000 9 d e f matchType(x: Any): String = x match {10 ”A String assignment after sleep” 10 c a s e : I n t= > ”Int” 11 } 11 c a s e : S t r i n g= > ”String” 12 12 c a s e => ”Something else” 13 a onComplete { 13 } 14 c a s e Success(str)= > p r i n t l n(str) 14 p r i n t l n (matchType(3.5) ) 15 c a s e Failure(t)= > 15 p r i n t l n(t.getMessage) 16 d e f matchOption(x: Option[String]) : 16 } S t r i n g = x match { 17 17 c a s e Some(str)= > s t r 18 p r i n t l n(”After declaration”) 18 c a s e None= > ”No String” 19 Await.result(a, 30 second) 19 } 20 } 20 p r i n t l n (matchOption(Some(”A string”))) 21 } Output:

Output: After declaration A String assignment after sleep many Something else A String Figure 10: Futures in Scala

Figure 9: Pattern Matching to be the more robust of the two implementations. The actor model has been used in other functional main thread. In figure 10, a future is declared on languages. Most notably for Scala is the Erlang line 8. This future will evaluate in its own thread. implementation of actors. Jonas Bon´ercredits this Starting on line 13, pattern matching is used to let implementation as being his guide for the Akka li- the future know what to do when it completes. In brary. the output, it can be seen that the println on line Actors are a method of message passing between 18 is executed before the println on line 9. This threads. A main thread of execution can define is because both threads are executing at the same the actors, and pass messages to the actors, as well time, but the future has a sleep statement which as let actors pass messages directly between each delays its println. other. The big advantage of actors is that the ac- Futures are a method of concurrent execution tors are agnostic to which machine they are on. that will be familiar to AJAX programmers. Fu- The implementation of actors is similar if they are tures allow a second thread to be generated so exe- running as separate threads on the same machine, cution of the first thread is not blocked during the or threads on different machines. Actors allow a evaluation. method of developing large, scalable applications across multiple machines. Figure 11 shows a basic hello world with an 3 Akka Actors actor[5]. The actor is defined on lines 2-7, and the main thread starts on line 8. In this example, a The Akka library was originally developed by Jonas single actor is created. Pattern matching is used to Bon´er.The core Scala library also includes an actor match the messages sent to the actor and different implementation, but the Akka library is considered println’s are executed depending on the message.

5 1 import akka.actor. { Actor, Props, ActorSystem } 2 c l a s s HelloActor extends Actor { 3 d e f receive = { 4 c a s e”hello”= > p r i n t l n(”hello back at 1 c l a s s HelloActor extends Actor { you”) 2 d e f receive = { 5 c a s e => p r i n t l n(”huh?”) 3 c a s e”hello”= > { 6 } 4 Thread sleep 2000 7 } 5 p r i n t l n(”hello back at you”) 8 o b j e c t Main extends App { 6 } 9 v a l system = ActorSystem(”HelloSystem”) 7 c a s e => { 10 v a l helloActor = 8 Thread sleep 1000 system.actorOf(Props[HelloActor] , name 9 p r i n t l n(”huh?”) =”helloactor”) 10 } 11 helloActor !”hello” 11 } 12 helloActor !”buenos dias” 12 } 13 } hello back at you hello back at you huh? huh? Figure 12: An actor whose responses take different Figure 11: An actor hello world execution times.

On lines 11 and 12, two messages are sent to the actor, and in the output, the response of the actor to those messages can be seen. The actor in figure 11 can be redefined to the actor in figure 12. During execution, the same two messages are sent to this actor, but now the ac- tor will still be processing the first message when it 1 o b j e c t Main extends App { 2 v a l system = ActorSystem(”ha”) receives the second. As can be seen from the out- 3 v a l ha1 = put, the order of the println’s executed by the new system.actorOf(Props[HelloActor] , name actor is the same as figure 11. The actor receives =”ha1”) the second message while it is processing the first 4 v a l ha2 = system.actorOf(Props[HelloActor] , name message. The message will wait on the actors mes- =”ha2”) sage queue while the actor is completing execution 5 v a l routerProps = of the first message. Only once the first message Props .empty. withRouter(RoundRobinRouter( has been completed does the actor start processing 6 routees = Vector(ha1,ha2))) 7 v a l router = system.actorOf(routerProps) the second message. 8 r o u t e r !”hello” In figure 13, the main method is changed. Two 9 r o u t e r !”buenos dias” copies of the actor are instantiated and a router10 } is used to send messages. Akka provides a several different pre-built routers, as well as allowing the huh? programmer to define their own routers[6]. In this hello back at you example, a pre-built round robin router is being used. The router will direct messages between the two actors, and each actor will execute in its own Figure 13: Creating a pool of actors thread. As can be seen from the output, the sec- ond message completes execution before the first message.

6 Actors provide a flexible way of creating scalable 2014. Web. 17 Nov. 2014. concurrent applications. Both Scala and Akka pro- . ing with Scala 2.10, the Scala actor model was deprecated[7]. Typesafe is continuing to make [3] ““functions Are First Class Values” What Does Akka the default actor model. This Exactly Mean?” Scala. Web. 17 Nov. 2014. .

Scala provides a number of additional constructs [4] “How Does Yield Work?” Faq. Web. for parallel programming. The basic constructs of 17 Nov. 2014. . from Java. However, we program in high level lan- [5] “Simple Scala Akka Actor Examples guages to speed up development time and increase (Hello, World Examples).” Scala, Java, code readability. The additional parallel program- Linux, Mac Os X, Iphone, Perl, Dru- ming methods, parallel collections, futures, and ac- pal, Tutorials. Web. 17 Nov. 2014. tors, help programmers quickly write parallel code . [6] “Routing.” Akka Documen- References tation. Web. 17 Nov. 2014. . Wikipedia. Wikimedia Foundation, 16 Nov. 2014. Web. 17 Nov. 2014. [7] “The Scala Actors Migration Guide.” . Nov. 2014. . Wikimedia Foundation, 16 Nov.

7