Modern Functional Programming and Actors With Scala and Akka

Similar documents
Clojure Concurrency Constructs, Part Two. CSCI 5828: Foundations of Software Engineering Lecture 13 10/07/2014

Communicating Scala Objects. Bernard Sufrin. CPA, York, September 2008

Python & Numpy A tutorial

Functional Programming with F# Overview and Basic Concepts

Multicore Semantics and Programming

Python. chrysn

ECE521 W17 Tutorial 1. Renjie Liao & Min Bai

Computer Science Introductory Course MSc - Introduction to Java

Lab Course: distributed data analytics

Actors for Reactive Programming. Actors Origins

Object Oriented Software Design (NTU, Class Even, Spring 2009) Final Examination Problem Sheet TIME: 06/16/2009, 14:20 17:20

6.001 Recitation 22: Streams

INF Models of concurrency

11 Parallel programming models

INF 4140: Models of Concurrency Series 3

Big-O Notation and Complexity Analysis

Blocking Synchronization: Streams Vijay Saraswat (Dec 10, 2012)

Introduction to Python

Applied C Fri

Notes from Yesterday s Discussion. Big Picture. CIS 500 Software Foundations Fall November 1. Some lessons.

Course Announcements. Bacon is due next Monday. Next lab is about drawing UIs. Today s lecture will help thinking about your DB interface.

Real Time Operating Systems

Inter-Reactive Kotlin Applications

Socket Programming. Daniel Zappala. CS 360 Internet Programming Brigham Young University

Maps performance tips On server: Maintain DB connections, prepared statements (per thread/request!)

Big Data Infrastructure CS 489/698 Big Data Infrastructure (Winter 2016)

Introduction to lambda calculus Part 6

Towards a Practical Secure Concurrent Language

Information Security Theory vs. Reality

Simply Typed Lambda Calculus

COMP 204. Object Oriented Programming (OOP) Mathieu Blanchette

rethinking software design by analyzing state

Introduction to ASM - ByteCode Manipulating Tool

Design of Distributed Systems Melinda Tóth, Zoltán Horváth

Languages, regular languages, finite automata

Nunchaku: Flexible Model Finding for Higher-Order Logic

Turing Machines Part Three

A Universal Calculus for Stream Processing Languages

Static Program Analysis

ECS 120 Lesson 18 Decidable Problems, the Halting Problem

APPENDIX A FASTFLOW A.1 DESIGN PRINCIPLES

Notater: INF3331. Veronika Heimsbakk December 4, Introduction 3

Appendix 2: Linear Algebra

Functional Big-step Semantics

Universal Turing Machine. Lecture 20

ITI Introduction to Computing II

Formal verification of IA-64 division algorithms

CS 6110 Lecture 28 Subtype Polymorphism 3 April 2013 Lecturer: Andrew Myers

Computability Crib Sheet

Simple Bivalency Proofs of the Lower Bounds in Synchronous Consensus Problems

Scripting Languages Fast development, extensible programs

UNIT-III REGULAR LANGUAGES

Introduction. How to use this book. Linear algebra. Mathematica. Mathematica cells

Adapted with permission from: Seif Haridi KTH Peter Van Roy UCL. C. Varela; Adapted w. permission from S. Haridi and P. Van Roy 1

Constructors - Cont. must be distinguished by the number or type of their arguments.

STAT 3008 Applied Regression Analysis Tutorial 1: Introduction LAI Chun Hei

Real-Time Scheduling. Real Time Operating Systems and Middleware. Luca Abeni

Using the Principles of Synchronous Languages in Discrete-event and Continuous-time Models

Compiling Techniques

Improper Nesting Example

MURA Office hours Thurs at 12-1pm in CIT 546 Contact for more info.

Computational Tasks and Models

Lisp Introduction. Dr. Neil T. Dantam. Spring CSCI-498/598 RPM, Colorado School of Mines. Dantam (Mines CSCI, RPM) Lisp Spring / 88

Introduction to Python

Computer Science Introductory Course MSc - Introduction to Java

Practical Data Processing With Haskell

A Reconfigurable Quantum Computer

Functions in Python L435/L555. Dept. of Linguistics, Indiana University Fall Functions in Python. Functions.

Comp 11 Lectures. Mike Shah. July 26, Tufts University. Mike Shah (Tufts University) Comp 11 Lectures July 26, / 40

Python. Tutorial. Jan Pöschko. March 22, Graz University of Technology

Distributed Architectures

Let us first give some intuitive idea about a state of a system and state transitions before describing finite automata.

Comp 11 Lectures. Dr. Mike Shah. August 9, Tufts University. Dr. Mike Shah (Tufts University) Comp 11 Lectures August 9, / 34

14 Random Variables and Simulation

Relational Algebra & Calculus

Safety Analysis versus Type Inference

CS429: Computer Organization and Architecture

INF Models of concurrency

Nondeterminism. September 7, Nondeterminism

EE 144/244: Fundamental Algorithms for System Modeling, Analysis, and Optimization Fall 2016

Decidability: Church-Turing Thesis

Agile modeling for INF5150

Marwan Burelle. Parallel and Concurrent Programming. Introduction and Foundation

Programming Languages Fall 2013

L435/L555. Dept. of Linguistics, Indiana University Fall 2016

Limitations of OCAML records

And, even if it is square, we may not be able to use EROs to get to the identity matrix. Consider

Virtualization. Introduction. G. Lettieri A/A 2014/15. Dipartimento di Ingegneria dell Informazione Università di Pisa. G. Lettieri Virtualization

ITI Introduction to Computing II

MA/CSSE 474 Theory of Computation

CS1800: Hex & Logic. Professor Kevin Gold

2.6 Variations on Turing Machines

USING SAT FOR COMBINATIONAL IMPLEMENTATION CHECKING. Liudmila Cheremisinova, Dmitry Novikov

Scikit-learn. scikit. Machine learning for the small and the many Gaël Varoquaux. machine learning in Python

Classical Program Logics: Hoare Logic, Weakest Liberal Preconditions

ECEN 651: Microprogrammed Control of Digital Systems Department of Electrical and Computer Engineering Texas A&M University

Programming Language Concepts, CS2104 Lecture 3

Discrete-event simulations

Design Patterns and Refactoring

Sharing Objects. Pieter van den Hombergh. Fontys Hogeschool voor Techniek en Logistiek. February 15, 2017

Transcription:

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

1 o b j e c t VarValDeclarations { 2 var a = 1 3 v a l b = 2 4 v a l c : I n t=3 5 d e f afunction ( value : I n t ) : I n t = { 6 value 8 d e f bfunction ( value : Any) = { 9 value 10 } 1 o b j e c t f i r s t C l a s s F u n c t i o n s { 2 d e f f ( x : I n t ) = x + 2 ; 3 p r i n t l n ( Array ( 1, 2, 3 ). map( f ) ) 4 } Array(3, 4, 5) Figure 2: First class functions in Scala Figure 1: Variable and Value declarations 2 Scala Traditionally, Object oriented programming has been a subset of procedural languages, with languages like C++ and Java. In 2003, Martin Odersky developed Scala for his programming language class at École Polytechnique Fédérale de Lausanne[1]. He wanted to show that object oriented programming was compatible with functional programming. Strictly speaking, Scala is not a functional programming language, nor is it a procedural language. Scala fully supports both forms of programming. Scala is built on top of the JVM, and compiles to Java bytecode. As such, Scala is compatible with Java libraries, and Scala libraries are compatible with Java. Scala addresses one of the limiting factors of previous functional languages, in that it allows the programmer to use procedural programming when required. 2.1 Scala Language Basics Scala has a philosophy of offloading much of the typing to the compiler. Like Java, Scala is a strongly typed language, but the type is usually inferred by the compiler at compile time. Lines 3 and 4 of figure 1 show the declaration of two integers. On line 3, the type is inferred by the compiler, and on line 4, the type is explicitly set by the programmer. Scala also supports variables and values. Variables work as expected from other languages. Values are the immutable variant of variables. Scala, in general, prefers immutable objects. An example of Scala s preference for immutability is in the Scala collections. By default the members of a collection are immutable, unless a mutable collection is imported by the programmer. A last thing to notice in figure 1 is that the functions do not have an explicit return statement. Scala does support the return keyword, but will default to returning the last line of a function block. This makes sense given Scala s functional influence. Function s with no return, or void functions, are used to create side effects, but since functional languages try to eliminate side effects, every function should have a return value. Figure 2 shows how functions can be used as first class objects in Scala. This is a standard feature of functional programming, where a functions can be used in the same manner as other types. In this example, the function f is used as an argument to the map function[3]. As can be seen from figure 3, Scala and Java are similar. One important difference is that unlike Java, Scala supports the Singleton Design Pattern at the language level. In Scala, an object is a singleton. Since Scala is object oriented, it also supports classes and an object hierarchy like Java s. 2.2 For Yield Condition/Map Filter Scala supports functional constructs, such as maps. In figures 4, 5 and 6 show examples of Scala s foryield syntax. In figure 4, maps are used to generate a cartesian product. In figure 5, a for-yield statement is used. At compilation, the code in figure 5 is converted into code similar to figure 4, however, depending on the situation, one may be more readable than the other[4]. In figure 6, a condition is added to the for statement, removing symmetric results. A similar condition can be applied to the map syntax. 2

Listing 1: Java Hello World 1 p u b l i c c l a s s HelloJava { 2 p u b l i c s t a t i c void main ( S t r i n g [ ] a r g s ) { 3 System. out. p r i n t l n ( H e l l o Java ) ; 4 } 5 } Listing 2: Scala Hello World 1 o b j e c t H e l l o S c a l a { 2 d e f main ( a r g s : Array [ S t r i n g ] ) { 3 p r i n t l n ( H e l l o S c a l a ) 4 } 5 } Figure 3: Hello Worlds in Scala and Java Listing 3: Sequential Loop Execution 1 o b j e c t ParallelExample extends App{ 2 v a l i n t e g e r s =1 u n t i l 5 3 v a l timestable=f o r ( i n t e g e r 1 < i n t e g e r s ) y i e l d { 4 f o r ( i n t e g e r 2 < i n t e g e r s ) y i e l d { 5 i n t e g e r 1 i n t e g e r 2 8 timestable. f o r e a c h ( p r i n t l n ( ) ) Listing 4: Parallel Loop Execution 1 o b j e c t ParallelExample extends App{ 2 v a l i n t e g e r s =1 u n t i l 5 3 v a l timestable=f o r ( i n t e g e r 1 < i n t e g e r s. par ) y i e l d { 4 f o r ( i n t e g e r 2 < i n t e g e r s ) y i e l d { 5 i n t e g e r 1 i n t e g e r 2 8 timestable. f o r e a c h ( p r i n t l n ( ) ) Vector(1, 2, 3, 4) Vector(2, 4, 6, 8) Vector(3, 6, 9, 12) Vector(4, 8, 12, 16) Vector(1, 2, 3, 4) Vector(2, 4, 6, 8) 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 { 2 v a l p o i n t s = 0 u n t i l 5 3 v a l c a r t e s s i a n P r o d u c t = p o i n t s. flatmap ( x => p o i n t s. map( y => ( x, y ) ) ) 4 p r i n t l n ( c a r t e s s i a n P r o d u c t ) 5 } Vector((0,0), (0,1)...(6,6)) Figure 4: Map Syntax 1 o b j e c t CartesianProduct extends App { 2 v a l p o i n t s = 0 u n t i l 5 3 v a l c a r t e s s i a n P r o d u c t=f o r {x< p o i n t s 4 y< p o i n t s } y i e l d { 5 ( x, y ) 7 p r i n t l n ( c a r t e s s i a n P r o d u c t ) 8 } Vector((0,0), (0,1)...(6,6)) Figure 5: For Yield Syntax 3

1 o b j e c t ParallelExample extends App { 2 v a l i n t e g e r s = 1 u n t i l 5 3 v a l timestable = f o r ( i n t e g e r 1 < i n t e g e r s ) y i e l d { 4 f o r { i n t e g e r 2 < i n t e g e r s 5 i f ( i n t e g e r 2 <= i n t e g e r 1 ) y i e l d { 7 i n t e g e r 1 i n t e g e r 2 8 } 10 timestable. f o r e a c h ( p r i n t l n ( ) ) Vector(1) Vector(2, 4) Vector(3, 6, 9) Vector(4, 8, 12, 16) Figure 6: Conditional For Yield Listing 5: Parallel Loop Execution 1 import s c a l a. c o l l e c t i o n. p a r a l l e l. ParSeq 2 3 o b j e c t ParallelExample extends App{ 4 v a l i n t e g e r s=parseq ( 1, 2, 3, 4 ) 5 v a l timestable=f o r ( i n t e g e r 1 < i n t e g e r s ) y i e l d { 6 f o r ( i n t e g e r 2 < i n t e g e r s ) y i e l d { 7 i n t e g e r 1 i n t e g e r 2 8 } 10 timestable. f o r e a c h ( p r i n t l n ( ) ) ParArray(1, 2, 3, 4) ParArray(4, 8, 12, 16) ParArray(3, 6, 9, 12) ParArray(2, 4, 6, 8) Figure 8: Parallel Collections 2.3 Parallel Execution of Collections The first example of parallel computation methods that exist in Scala, but not Java, can be seen in figure 7. In this case, the.par operator is added on line 3. The code on the left executes sequentially, the code on the right is executed in parallel. By adding the.par operator, Scala knows to treat that collection as parallel. While executing, it will determine how many threads are available, create the threads, parse parts of the collection to each thread and then join the results. It should be noted that the resulting collection timestable is no longer deterministic and may change between different executions of the code. This is why the third and fourth lines of the output have reversed order from the original output. This parallelization of mappings can be done in other languages, but its execution is much simpler in Scala. In fact, Scala supports a large range of collection implementations. Some common ones are Seq, which is similar to an Array in Java, List, which is similar to an ArrayList in Java, and Stream, a collection type that was added to Java 8 in which the individual members have lazy evaluation. For most collections, Scala also supports a parallel version. In figure 8, the code has been changed to use a parallel collection instead of a sequential collection. Similar to the previous parallel example, the order of rows is not deterministic. In this example, the order of the columns has been preserved, but this can not be relied on. Parallel collections provide a simple, powerful data type for processing large collections where the order of the collection is not important. 2.4 Pattern Matching Another important feature of Scala is pattern matching. Pattern matching is used in several ways in Scala. In figure 9, several examples of pattern matching can be seen. The first example is pattern matching on value, the second is pattern matching on type, and the third is using the Option data type. Option is a wrapper for optional values. It is used for passing optional data. Each example of pattern matching can be further developed to provide more complex behaviours. 2.5 Concurrent Execution of Futures Futures are another method of parallel execution in Scala. Futures generate a new thread, where the future is evaluated. While the future is evaluating, the main thread of execution is still processing. When the future completes, it return to the 4

1 o b j e c t PatternMatching extends App { 2 d e f matchvalue ( x : I n t ) : S t r i n g = x match { 3 c a s e 1 => one 4 c a s e 2 => two 5 c a s e => many 7 p r i n t l n ( matchvalue ( 3 ) ) 8 9 d e f matchtype ( x : Any) : S t r i n g = x match { 10 A S t r i n g assignment a f t e r s l e e p 10 c a s e : I n t => I n t 11 c a s e : S t r i n g => S t r i n g 12 12 c a s e => Something e l s e 13 } 14 p r i n t l n ( matchtype ( 3. 5 ) ) 15 16 d e f matchoption ( x : Option [ S t r i n g ] ) : S t r i n g = x match { 17 c a s e Some ( s t r ) => s t r 18 c a s e None => No S t r i n g 1 20 p r i n t l n ( matchoption ( Some ( A s t r i n g ) ) ) 21 } many Something else A String 1 import s c a l a. c o n c u r r e n t. 2 import s c a l a. c o n c u r r e n t. d u r a t i o n. 3 import s c a l a. c o n c u r r e n t. ExecutionContext 4. I m p l i c i t s. g l o b a l 5 import s c a l a. u t i l. { F a i l u r e, S u c c e s s } 6 7 o b j e c t FuturesExample extends App{ 8 v a l a : Future [ S t r i n g ] = f u t u r e { 9 Thread s l e e p 1000 13 a oncomplete { 14 c a s e S u c c e s s ( s t r ) => p r i n t l n ( s t r ) 15 c a s e F a i l u r e ( t ) => p r i n t l n ( t. getmessage ) 1 17 18 p r i n t l n ( A f t e r d e c l a r a t i o n ) 19 Await. r e s u l t ( a, 30 second ) 20 } After declaration A String assignment after sleep Figure 10: Futures in Scala Figure 9: Pattern Matching main thread. In figure 10, a future is declared on line 8. This future will evaluate in its own thread. Starting on line 13, pattern matching is used to let the future know what to do when it completes. In the output, it can be seen that the println on line 18 is executed before the println on line 9. This is because both threads are executing at the same time, but the future has a sleep statement which delays its println. Futures are a method of concurrent execution that will be familiar to AJAX programmers. Futures allow a second thread to be generated so execution of the first thread is not blocked during the evaluation. 3 Akka Actors The Akka library was originally developed by Jonas Bonér. The core Scala library also includes an actor implementation, but the Akka library is considered to be the more robust of the two implementations. The actor model has been used in other functional languages. Most notably for Scala is the Erlang implementation of actors. Jonas Bonér credits this implementation as being his guide for the Akka library. Actors are a method of message passing between threads. A main thread of execution can define the actors, and pass messages to the actors, as well as let actors pass messages directly between each other. The big advantage of actors is that the actors are agnostic to which machine they are on. The implementation of actors is similar if they are running as separate threads on the same machine, or threads on different machines. Actors allow a method of developing large, scalable applications across multiple machines. Figure 11 shows a basic hello world with an actor[5]. The actor is defined on lines 2-7, and the main thread starts on line 8. In this example, a single actor is created. Pattern matching is used to match the messages sent to the actor and different println s are executed depending on the message. 5

1 import akka. a c t o r. { Actor, Props, ActorSystem } 2 c l a s s HelloActor extends Actor { 3 d e f r e c e i v e = { 4 c a s e h e l l o => p r i n t l n ( h e l l o back at you ) 5 c a s e => p r i n t l n ( huh? ) 8 o b j e c t Main extends App { 9 v a l system = ActorSystem ( HelloSystem ) 10 v a l h e l l o A c t o r = system. actorof ( Props [ HelloActor ], = h e l l o a c t o r ) 11 h e l l o A c t o r! h e l l o 12 h e l l o A c t o r! buenos d i a s 13 } name 1 c l a s s HelloActor extends Actor { 2 d e f r e c e i v e = { 3 c a s e h e l l o => { 4 Thread s l e e p 2000 5 p r i n t l n ( h e l l o back at you ) 7 c a s e => { 8 Thread s l e e p 1000 9 p r i n t l n ( huh? ) 10 } 12 } hello back at you huh? Figure 11: An actor hello world hello back at you huh? Figure 12: An actor whose responses take different 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 actor 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 output, the order of the println s executed by the new system. actorof ( Props [ HelloActor ], 3 v a l ha1 = = ha1 ) name actor is the same as figure 11. The actor receives 4 v a l ha2 = the second message while it is processing the first system. actorof ( Props [ HelloActor ], name message. The message will wait on the actors message queue while the actor is completing execution 5 v a l rou terprops = = ha2 ) of the first message. Only once the first message Props. empty. withrouter ( RoundRobinRouter ( 6 r o u t e e s = Vector ( ha1, ha2 ) ) ) has been completed does the actor start processing 7 v a l r o u t e r = system. actorof ( r o u t e r P r o p s ) the second message. 8 r o u t e r! h e l l o In figure 13, the main method is changed. Two 9 r o u t e r! buenos d i a s copies of the actor are instantiated and a router is used to send messages. Akka provides a several different pre-built routers, as well as allowing the programmer to define their own routers[6]. In this 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 thread. As can be seen from the output, the second message completes execution before the first message. 10 } huh? hello back at you Figure 13: Creating a pool of actors 6

Actors provide a flexible way of creating scalable concurrent applications. Both Scala and Akka provide implementations of the actor model. Starting with Scala 2.10, the Scala actor model was deprecated[7]. Typesafe is continuing to make Akka the default actor model. 4 Conclusion Scala provides a number of additional constructs for parallel programming. The basic constructs of Semaphores and Mutex s exist, Scala inherits these from Java. However, we program in high level languages to speed up development time and increase code readability. The additional parallel programming methods, parallel collections, futures, and actors, help programmers quickly write parallel code and increase the readability of that code. References [1] Scala Programming Language. Wikipedia. Wikimedia Foundation, 16 Nov. 2014. Web. 17 Nov. 2014. <http://en.wikipedia.org/wiki/scala (programming language) >. [2] Functional Programming. Wikipedia. Wikimedia Foundation, 16 Nov. 2014. Web. 17 Nov. 2014. <http://en.wikipedia.org/wiki/functional programming>. [3] functions Are First Class Values What Does This Exactly Mean? Scala. Web. 17 Nov. 2014. <http://stackoverflow.com/questions/10777333/ functions-are-first-class-values-what- does-thisexactly-mean>. [4] How Does Yield Work? Faq. Web. 17 Nov. 2014. <http://docs.scalalang.org/tutorials/faq/yield.html>. [5] Simple Scala Akka Actor Examples (Hello, World Examples). Scala, Java, Linux, Mac Os X, Iphone, Perl, Drupal, Tutorials. Web. 17 Nov. 2014. <http://alvinalexander.com/scala/simplescala-akka-actor-examples-hello-world-actors>. [6] Routing. Akka Documentation. Web. 17 Nov. 2014. <http://doc.akka.io/docs/akka/snapshot/scala/ routing.html>. [7] The Scala Actors Migration Guide. - Scala Documentation. Web. 17 Nov. 2014. <http://docs.scalalang.org/overviews/core/actors-migrationguide.html>. 7