Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Learning Concurrent Programming in Scala: Chapter No. 1 "Introduction"

Download as pdf or txt
Download as pdf or txt
You are on page 1of 21

Learning Concurrent

Programming in Scala

Aleksandar Prokopec

Chapter No. 1
"Introduction"

In this package, you will find:


The authors biography
A preview chapter from the book, Chapter no.1 "Introduction"
A synopsis of the books content
Information on where to buy this book

About the Author


Aleksandar Prokopec is a software developer and a concurrent and distributed
programming researcher. He holds an MSc in Computing from the Faculty of Electrical
Engineering and Computing, University of Zagreb, Croatia, and a PhD in Computer
Science from the cole Polytechnique Fdrale de Lausanne, Switzerland. As a doctoral
assistant and member of the Scala team at EPFL, he actively contributed to the Scala
programming language, and has worked on programming abstractions for concurrency,
data-parallel programming support, and concurrent data structures for Scala. He created
the Scala Parallel Collections framework, which is a library for high-level data-parallel
programming in Scala, and participated in working groups for Scala concurrency
libraries, such as Futures and Promises and ScalaSTM.

For More Information:


www.packtpub.com/application-development/learning-concurrentprogramming-scala

Acknowledgments
First of all, I would like to thank my reviewers Samira Tasharofi , Lukas Rytz, Dominik
Gruntz, Michel Schinz, Zhen Li, and Vladimir Kostyukov for their excellent feedback
and valuable comments. They have shown exceptional dedication and expertise in
improving the quality of this book. I would also like to thank the editors at Packt
Publishing: Kevin Colaco, Sruthi Kutty, Kapil Hemnani, Vaibhav Pawar, and Sebastian
Rodrigues for their help in writing this book. It was really a pleasure to work with
these people.
The concurrency frameworks described in this book wouldn't have seen the light of day
without a collaborative effort of a large number of people. Many individuals have, either
directly or indirectly, contributed to the development of these utilities. These people are
the true heroes of Scala concurrency, and they deserve thanks for Scala's excellent
support for concurrent programming. It is difficult to enumerate all of them here, but I
have tried my best. If somebody feels left out, he should ping me, and he'll probably
appear in the next edition of this book.
It goes without saying that Martin Odersky is to be thanked for creating the Scala
programming language, which was used as a platform for the concurrency frameworks
described in this book. Special thanks go to him, to all the people who were a part of the
Scala team at the EPFL for the last 10 or more years, and to the people at Typesafe, who
are working hard to make Scala one of the best general-purpose languages out there.
Most of the Scala concurrency frameworks rely on the works of Doug Lea in one way or
another. His Fork/Join framework underlies the implementation of the Akka actors, Scala
Parallel collections, and the Futures and Promises library; and many of the JDK
concurrent data structures described in this book are his own implementations. Many of
the Scala concurrency libraries were influenced by his advice. Furthermore, I would like
to thank the Java concurrency experts for the years of work they invested into making
JVM a solid concurrency platform, and especially, Brian Goetz, whose book inspired
our front cover.
The Scala Futures and Promises library was initially designed by Philipp Haller, Heather
Miller, Vojin Jovanovi, and myself, from the EPFL; Viktor Klang and Roland Kuhn
from the Akka team; Marius Eriksen from Twitter; with contributions from Havoc
Pennington, Rich Dougherty, Jason Zaugg, Doug Lea, and many others.
Although I was the main author of the Scala Parallel Collections, this library benefited
from the input of many different people, including Phil Bagwell, Martin Odersky, Tiark
Rompf, Doug Lea, and Nathan Bronson. Later on, Dmitry Petrashko and I started
working on an improved version of parallel and standard collection operations, which
were optimized through the use of Scala Macros. Eugene Burmako and Denys Shabalin
are among the main contributors to the Scala Macros project.

For More Information:


www.packtpub.com/application-development/learning-concurrentprogramming-scala

The work on the Rx project was started by Erik Meijer, Wes Dyer, and the rest of theRx
team. Since its original .NET implementation, the Rx framework has been ported to many
different languages, including Java, Scala, Groovy, JavaScript, and PHP, and has gained
widespread adoption, thanks to the contributions and the maintenance work of Ben
Christensen, Samuel Grtter, Shixiong Zhu, Donna Malayeri, and many other people.
Nathan Bronson is one of the main contributors to the ScalaSTM project, whose default
implementation is based on Nathan's CCSTM project. The ScalaSTM API was designed
by the ScalaSTM expert group, which comprised of Nathan Bronson, Jonas Bonr, Guy
Korland, Krishna Sankar, Daniel Spiewak, and Peter Veentjer.
The initial Scala actor library was inspired by the Erlang actor model, and developed by
Philipp Haller. This library inspired Jonas Bonr to start the Akka actor framework. The
Akka project had many contributors, including Viktor Klang, Henrik Engstrm, Peter
Vlugter, Roland Kuhn, Patrik Nordwall, Bjrn Antonsson, Rich Dougherty, Johannes
Rudolph, Mathias Doenitz, Philipp Haller, and many others.
Finally, I would like to thank the entire Scala community for their contributions, and for
making Scala an awesome programming language.

For More Information:


www.packtpub.com/application-development/learning-concurrentprogramming-scala

Learning Concurrent
Programming in Scala
Concurrency is everywhere. With the rise of multicore processors in the consumer
market, the need for concurrent programming has overwhelmed the developer world.
Where it once served to express asynchrony in programs and computer systems, and was
largely an academic discipline, concurrent programming is now a pervasive methodology
in software development. As a result, advanced concurrency frameworks and libraries are
sprouting at an amazing rate. Recent years have witnessed a renaissance in the field of
concurrent computing.
As the level of abstraction grows in modern languages and concurrency frameworks, it
is becoming crucial to know how and when to use them. Having a good grasp of the
classical concurrency and synchronization primitives, such as threads, locks, and
monitors, is no longer sufficient. High-level concurrency frameworks, which solve
many issues of traditional concurrency and are tailored towards specific tasks, are
gradually overtaking the world of concurrent programming.
This book describes high-level concurrent programming in Scala. It presents detailed
explanations of various concurrency topics and covers the basic theory of concurrent
programming. Simultaneously, it describes modern concurrency frameworks, shows
their detailed semantics, and teaches you how to use them. Its goal is to introduce
important concurrency abstractions, and at the same time show how they work in
real code.
We are convinced that, by reading this book, you will gain both a solid theoretical
understanding of concurrent programming, and develop a set of useful practical skills
that are required to write correct and efficient concurrent programs. These skills are
the first steps toward becoming a modern concurrency expert.
We hope that you will have as much fun reading this book as we did writing it.
The goal of this book is not to give a comprehensive overview of every dark corner of the
Scala concurrency APIs. Instead, this book will teach you the most important concepts of
concurrent programming. By the time you are done reading this book, you will not just be
able to find additional information in the online documentation; you will also know what
to look for. Rather than serving as a complete API reference and feeding you the exact
semantics of every method, the purpose of this book is to teach you how to fish. By the
time you are done reading, you will not only understand how different concurrency
libraries work, but you will also know how to think when building a concurrent program.

For More Information:


www.packtpub.com/application-development/learning-concurrentprogramming-scala

What This Book Covers


This book is organized into a sequence of chapters with various topics on concurrent
programming. The book covers the fundamental concurrent APIs that are a part of the
Scala runtime, introduces more complex concurrency primitives, and gives an extensive
overview of high-level concurrency abstractions.
Chapter 1, Introduction, explains the need for concurrent programming, and gives some
philosophical background. At the same time, it covers the basics of the Scala
programming language that are required for understanding the rest of this book.
Chapter 2, Concurrency on the JVM and the Java Memory Model, teaches you the basics
of concurrent programming. This chapter will teach you how to use threads, how to
protect access to shared memory, and introduce the Java Memory Model.
Chapter 3, Traditional Building Blocks of Concurrency, presents classic concurrency
utilities, such as thread pools, atomic variables, and concurrent collections with a
particular focus on the interaction with the features of the Scala language. The
emphasis in this book is on the modern, high-level concurrent programming
frameworks. Consequently, this chapter presents an overview of traditional concurrent
programming techniques, but it does not aim to be extensive.
Chapter 4, Asynchronous Programming with Futures and Promises, is the first chapter
that deals with a Scala-specific concurrency framework. This chapter presents the futures
and promises API, and shows how to correctly use them when implementing
asynchronous programs.
Chapter 5, Data-Parallel Collections, describes the Scala parallel collections framework.
In this chapter, you will learn how to parallelize collection operations, when it is allowed
to parallelize them, and how to assess the performance benefits of doing so.
Chapter 6, Concurrent Programming with Reactive Extensions, teaches you how to use
the Reactive Extensions framework for event-based and asynchronous programming.
You will see how the operations on event streams correspond to collection operations,
how to pass events from one thread to another, and how to design a reactive user
interface using event streams.
Chapter 7, Software Transactional Memory, introduces the ScalaSTM library for
transactional programming, which aims to provide a safer, more intuitive, sharedmemory programming model. In this chapter, you will learn how to protect access to
shared data using scalable memory transactions, and at the same time, reduce the risk of
deadlocks and race conditions.
Chapter 8, Actors, presents the actor programming model and the Akka framework. In
this chapter, you will learn how to transparently build message-passing distributed
programs that run on multiple machines.

For More Information:


www.packtpub.com/application-development/learning-concurrentprogramming-scala

Chapter 9, Concurrency in Practice, summarizes the different concurrency libraries


introduced in the earlier chapters. In this chapter, you will learn how to choose the correct
concurrency abstraction to solve a given problem, and how to combine different
concurrency abstractions together when designing larger concurrent applications.
While we recommend that you read the chapters in the order in which they appear, this is
not strictly necessary. If you are well acquainted with the content in Chapter 2,
Concurrency on the JVM and the Java Memory Model, you can study most of the other
chapters directly. The only chapter that heavily relies on the content from all the
preceding chapters is Chapter 9, Concurrency in Practice, where we present a practical
overview of the topics in this book.

For More Information:


www.packtpub.com/application-development/learning-concurrentprogramming-scala

Introduction
"For over a decade prophets have voiced the contention that the organization of a
single computer has reached its limits and that truly significant advances can be
made only by interconnection of a multiplicity of computers."
Gene Amdahl, 1967
Although the discipline of concurrent programming has a long history, it gained
a lot of traction in recent years with the arrival of multicore processors. The recent
development in computer hardware not only revived some classical concurrency
techniques, but also started a major paradigm shift in concurrent programming. At
a time, when concurrency is becoming so important, an understanding of concurrent
programming is an essential skill for every software developer.
This chapter explains the basics of concurrent computing and presents some Scala
preliminaries required for this book. Specifically, it does the following:

Shows a brief overview of concurrent programming


Studies the advantages of using Scala when it comes to concurrency
Covers the Scala preliminaries required for reading this book

We will start by examining what concurrent programming is and why it is important.

Concurrent programming
In concurrent programming, we express a program as a set of concurrent
computations that execute during overlapping time intervals and coordinate in some
way. Implementing a concurrent program that functions correctly is usually much
harder than implementing a sequential one. All the pitfalls present in sequential
programming lurk in every concurrent program, but there are many other things
that can go wrong, as we will learn in this book. A natural question arises: why
bother? Can't we just keep writing sequential programs?

For More Information:


www.packtpub.com/application-development/learning-concurrentprogramming-scala

Introduction

Concurrent programming has multiple advantages. First, increased concurrency


can improve program performance. Instead of executing the entire program on a
single processor, different subcomputations can be performed on separate processors
making the program run faster. With the spread of multicore processors, this is the
primary reason why concurrent programming is nowadays getting so much attention.
Then, a concurrent programming model can result in faster I/O operations. A
purely sequential program must periodically poll I/O to check if there is any data
input available from the keyboard, the network interface, or some other device. A
concurrent program, on the other hand, can react to I/O requests immediately. For
I/O-intensive operations, this results in improved throughput, and is one of the
reasons why concurrent programming support existed in programming languages
even before the appearance of multiprocessors. Thus, concurrency can ensure the
improved responsiveness of a program that interacts with the environment.
Finally, concurrency can simplify the implementation and maintainability of
computer programs. Some programs can be represented more concisely using
concurrency. It can be more convenient to divide the program into smaller,
independent computations than to incorporate everything into one large program.
User interfaces, web servers, and game engines are typical examples of such systems.
In this book, we adopt the convention that concurrent programs communicate
through the use of shared memory, and execute on a single computer. By contrast, a
computer program that executes on multiple computers, each with its own memory,
is called a distributed program, and the discipline of writing such programs is called
distributed programming. Typically, a distributed program must assume that each
of the computers can fail at any point, and provide some safety guarantees if this
happens. We will mostly focus on concurrent programs, but we will also look at
examples of distributed programs.

A brief overview of traditional concurrency


In a computer system, concurrency can manifest itself in the computer hardware,
at the operating system level, or at the programming language level. We will focus
mainly on programming language-level concurrency.
Coordination of multiple executions in a concurrent system is called synchronization,
and it is a key part in successfully implementing concurrency. Synchronization
includes mechanisms used to order concurrent executions in time. Furthermore,
synchronization specifies how concurrent executions communicate, that is, how
they exchange information. In concurrent programs, different executions interact
by modifying the shared memory subsystem of the computer. This type of
synchronization is called shared memory communication. In distributed programs,
executions interact by exchanging messages, so this type of synchronization is called
message-passing communication.
[ 14 ]

For More Information:


www.packtpub.com/application-development/learning-concurrentprogramming-scala

Chapter 1

At the lowest level, concurrent executions are represented by entities called processes
and threads, covered in Chapter 2, Concurrency on the JVM and the Java Memory Model.
Processes and threads traditionally use entities such as locks and monitors to order
parts of their execution. Establishing an order between the threads ensures that the
memory modifications done by one thread are visible to a thread that executes later.
Often, expressing concurrent programs using threads and locks is cumbersome.
More complex concurrent facilities have been developed to address this such as
communication channels, concurrent collections, barriers, countdown latches, and
thread pools. These facilities are designed to more easily express specific concurrent
programming patterns, and some of them are covered in Chapter 3, Traditional
Building Blocks of Concurrency.
Traditional concurrency is relatively low level and prone to various kinds of errors,
such as deadlocks, starvations, data races, and race conditions. You will rarely use
low-level concurrency primitives when writing concurrent Scala programs. Still,
a basic knowledge of low-level concurrent programming will prove invaluable in
understanding high-level concurrency concepts later.

Modern concurrency paradigms


Modern concurrency paradigms are more advanced than traditional approaches to
concurrency. Here, the crucial difference lies in the fact that a high-level concurrency
framework expresses which goal to achieve, rather than how to achieve that goal.
In practice, the difference between low-level and high-level concurrency is less clear,
and different concurrency frameworks form a continuum rather than two distinct
groups. Still, recent developments in concurrent programming show a bias towards
declarative and functional programming styles.
As we will see in Chapter 2, Concurrency on the JVM and the Java Memory Model,
computing a value concurrently requires creating a thread with a custom run
method, invoking the start method, waiting until the thread completes, and then
inspecting specific memory locations to read the result. Here, what we really want
to say is "compute some value concurrently, and inform me when you are done."
Furthermore, we would like to treat the result of the concurrent computation
as if we already have it, rather than having to wait for it, and then reading it
from the memory. Asynchronous programming using futures is a paradigm
designed to specifically support these kinds of statements, as we will learn in
Chapter 4, Asynchronous Programming with Futures and Promises. Similarly, reactive
programming using event streams aims to declaratively express concurrent
computations that produce many values, as we will see in Chapter 6, Concurrent
Programming with Reactive Extensions.
[ 15 ]

For More Information:


www.packtpub.com/application-development/learning-concurrentprogramming-scala

Introduction

The declarative programming style is increasingly common in sequential


programming too. Languages such as Python, Haskell, Ruby, and Scala express
operations on their collections in terms of functional operators, and allow statements
such as "filter all negative integers from this collection." This statement expresses
a goal rather than the underlying implementation, so it is easy to parallelize such
an operation behind the scene. Chapter 5, Data-Parallel Collections, describes the
data-parallel collections framework available in Scala, which is designed to
seamlessly accelerate collection operations using multiple processors.
Another trend seen in high-level concurrency frameworks is specialization towards
specific tasks. Software transactional memory technology is specifically designed
to express memory transactions, and does not deal with how to start concurrent
executions at all. A memory transaction is a sequence of memory operations that
appear as if they either execute all at once or do not execute at all. The advantage of
using memory transactions is that this avoids a lot of errors typically associated with
low-level concurrency. Chapter 7, Software Transactional Memory, explains software
transactional memory in detail.
Finally, some high-level concurrency frameworks aim to transparently provide
distributed programming support as well. This is especially true for data-parallel
frameworks and message passing concurrency frameworks, such as the actors
described in Chapter 8, Actors.

The advantages of Scala


Although Scala is still a language on the rise that has yet to receive the wide-scale
adoption of a language such as Java, its support for concurrent programming is rich
and powerful. Concurrency frameworks for nearly all the different styles of
concurrent programming exist in the Scala ecosystem, and are being actively
developed. Throughout its development, Scala has pushed the boundaries when it
comes to providing modern, high-level application programming interfaces or APIs
for concurrent programming. There are many reasons for this.
The primary reason that so many modern concurrency frameworks have found
their way into Scala is its inherent syntactic flexibility. Thanks to features such as
first-class functions, by-name parameters, type inference, and pattern matching
explained in the following sections, it is possible to define APIs that look as if they
are built-in language features.

[ 16 ]

For More Information:


www.packtpub.com/application-development/learning-concurrentprogramming-scala

Chapter 1

Such APIs emulate various programming models as embedded domain-specific


languages, with Scala serving as a host language: actors, software transactional
memory, and futures are examples of APIs that look like they are basic language
features, when they are in fact implemented as libraries. On one hand, Scala avoids the
need for developing a new language for each new concurrent programming model,
and serves as a rich nesting ground for modern concurrency frameworks. On the other
hand, lifting the syntactic burden present in many other languages attracts more users.
The second reason Scala has pushed ahead lies in the fact that it is a safe language.
Automatic garbage collection, automatic bound checks, and the lack of pointer
arithmetic help to avoid problems such as memory leaks, buffer overflows, and other
memory errors. Similarly, static type safety eliminates a lot of programming errors at
an early stage. When it comes to concurrent programming, which is in itself prone to
various kinds of concurrency errors, having one less thing to worry about can make
a world of difference.
The third important reason is interoperability. Scala programs are compiled into Java
bytecode, so the resulting executable code runs on top of the Java Virtual Machine
(JVM). This means that Scala programs can seamlessly use existing Java libraries,
and interact with Java's rich ecosystem. Often, transitioning to a different language
is a painful process. In the case of Scala, a transition from a language such as Java
can proceed gradually and is much easier. This is one of the reasons for its growing
adoption, and also a reason why some Java-compatible frameworks choose Scala as
their implementation language.
Importantly, the fact that Scala runs on the JVM implies that Scala programs are
portable across a range of different platforms. Not only that, but the JVM has
well-defined threading and memory models, which are guaranteed to work in the
same way on different computers. While portability is important for the consistent
semantics of sequential programs, it is even more important when it comes to
concurrent computing.
Having seen some of Scala's advantages for concurrent programming, we are now
ready to study the language features relevant for this book.

Preliminaries
This book assumes basic familiarity with sequential programming. While we advise
the readers to get acquainted with the Scala programming language, an understanding
of a similar language, such as Java or C#, should be sufficient for reading this book.
A basic familiarity with concepts in object-oriented programming, such as classes,
objects, and interfaces is helpful. Similarly, a basic understanding of functional
programming principles such as first-class functions, purity, and type-polymorphism
are beneficial in understanding this book, but are not a strict prerequisite.
[ 17 ]

For More Information:


www.packtpub.com/application-development/learning-concurrentprogramming-scala

Introduction

Execution of a Scala program


To better understand the execution model of Scala programs, let's consider a simple
program that uses the square method to compute the square value of the number
five, and then prints the result to the standard output:
object SquareOf5 extends App {
def square(x: Int): Int = x * x
val s = square(5)
println(s"Result: $s")
}

We can run this program using the Simple Build Tool (SBT), as described in the
Preface. When a Scala program runs, the JVM runtime allocates the memory required
for the program. Here, we consider two important memory regions: the call stack
and the object heap. The call stack is a region of memory in which the program
stores information about the local variables and parameters of the currently executed
methods. The object heap is a region of memory in which the objects are allocated by
the program. To understand the difference between the two regions, we consider a
simplified scenario of this program's execution.
First, in figure 1, the program allocates an entry to the call stack for the local variable
s. Then, it calls the square method in figure 2 to compute the value for the local
variable s. The program places the value 5 on the call stack, which serves as the
value for the x parameter. It also reserves a stack entry for the return value of the
method. At this point, the program can execute the square method, so it multiplies
the x parameter by itself, and places the return value 25 on the stack in figure 3. This
is shown in the first row in the following illustration:

[ 18 ]

For More Information:


www.packtpub.com/application-development/learning-concurrentprogramming-scala

Chapter 1

After the square method returns the result, the result 25 is copied into the stack
entry for the local variable s, as shown in figure 4. Now, the program must create the
string for the println statement. In Scala, strings are represented as object instances
of the String class, so the program allocates a new String object to the object heap,
as illustrated in figure 5. Finally, in figure 6, the program stores the reference to the
newly allocated object into the stack entry x, and calls the println method.
Although this demonstration is greatly simplified, it shows the basic execution
model for Scala programs. In Chapter 2, Concurrency on the JVM and the Java Memory
Model, we will learn that each thread of execution maintains a separate call stack,
and that threads mainly communicate by modifying the object heap. We will learn
that the disparity between the state of the heap and the local call stack is frequently
responsible for certain kinds of error in concurrent programs.
Having seen an example of how Scala programs are typically executed, we now
proceed to an overview of Scala features that are essential to understand the
contents of this book.

A Scala primer
In this section, we present a short overview of the Scala programming language
features that are used in the examples in this book. This is a quick and cursory glance
through the basics of Scala. Note that this section is not meant to be a complete
introduction to Scala. This is to remind you about some of the language's features,
and contrast them with similar languages that might be familiar to you. If you would
like to learn more about Scala, refer to some of the books referred in the summary
of this chapter.
A Printer class, which takes a greeting parameter, and has two methods named
printMessage and printNumber, is declared as follows:
class Printer(val greeting: String) {
def printMessage(): Unit = println(greeting + "!")
def printNumber(x: Int): Unit = {
println("Number: " + x)
}
}

In the preceding code, the printMessage method does not take any arguments,
and contains a single println statement. The printNumber method takes a single
argument x of the Int type. Neither method returns a value, which is denoted
by the Unit type. The Unit type can be omitted, in which case it is inferred
automatically by the Scala compiler.

[ 19 ]

For More Information:


www.packtpub.com/application-development/learning-concurrentprogramming-scala

Introduction

We instantiate the class and call its methods as follows:


val printy = new Printer("Hi")
printy.printMessage()
printy.printNumber(5)

Scala allows the declaration of singleton objects. This is like declaring a class and
instantiating its single instance at the same time. We saw the SquareOf5 singleton
object earlier, which was used to declare a simple Scala program. The following
singleton object, named Test, declares a single Pi field and initializes it with the
value 3.14:
object Test {
val Pi = 3.14
}

Where classes in similar languages extend entities that are called interfaces, Scala
classes can extend traits. Scala's traits allow declaring both concrete fields and
method implementations. In the following example, we declare the Logging trait
that outputs custom error and warning messages using the abstract log method,
and then mix the trait into the PrintLogging class:
trait
def
def
def
}
class
def
}

Logging {
log(s: String): Unit
warn(s: String) = log("WARN: " + s)
error(s: String) = log("ERROR: " + s)
PrintLogging extends Logging {
log(s: String) = println(s)

Classes can have type parameters. The following generic Pair class takes two type
parameters P and Q, which determine the types of its arguments, named first
and second:
class Pair[P, Q](val first: P, val second: Q)

Scala has support for first-class function objects, also called lambdas. In the following
code snippet, we declare a twice lambda, which multiplies its argument by two:
val twice: Int => Int = (x: Int) => x * 2

Downloading the example code


You can download the example code files for all Packt books you
have purchased from your account at http://www.packtpub.
com. If you purchased this book elsewhere, you can visit http://
www.packtpub.com/support and register to have the files
e-mailed directly to you.
[ 20 ]

For More Information:


www.packtpub.com/application-development/learning-concurrentprogramming-scala

Chapter 1

In the preceding code, the (x: Int) part is the argument to the lambda, and x *
2 is its body. The => symbol must be placed between the arguments and the body
of the lambda. The same => symbol is also used to express the type of the lambda,
which is Int => Int. In the preceding example, we can omit the type annotation
Int => Int, and the compiler will infer the type of the twice lambda automatically,
as shown in the following code:

val twice = (x: Int) => x * 2

Alternatively, we can omit the type annotation in the lambda declaration and arrive
at a more convenient syntax, as follows:
val twice: Int => Int = x => x * 2

Finally, whenever the argument to the lambda appears only once in the body of the
lambda, Scala allows a more convenient syntax, as follows:
val twice: Int => Int = _ * 2

First-class functions allow manipulating blocks of code as if they were first-class


values. They allow a more lightweight and concise syntax. In the following example,
we use by-name parameters to declare a runTwice method, which runs the specified
block of code body twice:
def runTwice(body: =>Unit) = {
body
body
}

A by-name parameter is formed by putting the => annotation before the type.
Whenever the runTwice method references the body argument, the expression
is re-evaluated, as shown in the following snippet:
runTwice { // this will print Hello twice
println("Hello")
}

Scala for expressions are a convenient way to traverse and transform collections.
The following for loop prints the numbers in the range from 0 until 10, where 10
is not included in the range:
for (i <- 0 until 10) println(i)

In the preceding code, the range is created with the expression 0 until 10, which
is equivalent to the expression 0.until(10), which calls the method until on
the value 0. In Scala, the dot notation can sometimes be dropped when invoking
methods on objects.
[ 21 ]

For More Information:


www.packtpub.com/application-development/learning-concurrentprogramming-scala

Introduction

Every for loop is equivalent to a foreach call. The preceding for loop is translated
by the Scala compiler to the following expression:
(0 until 10).foreach(i => println(i))

For-comprehensions are used to transform data. The following for-comprehension


transforms all the numbers from 0 until 10 by multiplying them by -1:
val negatives = for (i <- 0 until 10) yield -i

The negatives value contains negative numbers from 0 until -10. This forcomprehension is equivalent to the following map call:
val negatives = (0 until 10).map(i => -1 * i)

It is also possible to transform data from multiple inputs. The following forcomprehension creates all pairs of integers between zero and four:
val pairs = for (x <- 0 until 4; y <- 0 until 4) yield (x, y)

The preceding for-comprehension is equivalent to the following expression:


val pairs = (0 until 4).flatMap(x => (0 until 4).map(y => (x, y)))

We can nest an arbitrary number of generator expressions in a for-comprehension.


The Scala compiler will transform them into a sequence of nested flatMap calls,
followed by a map call at the deepest level.
Commonly used Scala collections include sequences, denoted by the Seq[T] type;
maps, denoted by the Map[T] type; and sets, denoted by the Set[T] type. In the
following code, we create a sequence of strings:
val messages: Seq[String] = Seq("Hello", "World.", "!")

Throughout this book, we rely heavily on the string interpolation feature. Normally,
Scala strings are formed with double quotation marks. Interpolated strings are
preceded with an s character, and can contain $ symbols with arbitrary identifiers
resolved from the enclosing scope, as shown in the following example:
val magic = 7
val myMagicNumber = s"My magic number is $magic"

Pattern matching is another important Scala feature. For readers with Java, C#,
or C background, it suffices to say that Scala's match statement is like the switch
statement on steroids. The match statement can decompose arbitrary datatypes,
and allows you to express different cases in the program concisely.

[ 22 ]

For More Information:


www.packtpub.com/application-development/learning-concurrentprogramming-scala

Chapter 1

In the following example, we declare a Map collection, named successors, used


to map integers to their immediate successors. We then call the get method to
obtain the successor of the number five. The get method returns an object with the
Option[Int] type, which may either be implemented with the Some class, indicating
that the number five exists in the map, or the None class, indicating that the number
five is not a key in the map. Pattern matching on the Option object allows proceeding
casewise, as shown in the following code snippet:
val successors = Map(1 -> 2, 2 -> 3, 3 -> 4)
successors.get(5) match {
case Some(n) => println(s"Successor is: $n")
case None
=> println("Could not find successor.")
}

In Scala, most operators can be overloaded. Operator overloading is no different


from declaring a method. In the following code snippet, we declare a Position
class with a + operator:
class Position(val x: Int, val y: Int) {
def +(that: Position) = new Position(x + that.x, y + that.y)
}

Finally, Scala allows defining package objects to store top-level method and value
definitions for a given package. In the following code snippet, we declare the
package object for the org.learningconcurrency package. We implement the
top-level log method, which outputs a given string and the current thread name:
package org
package object learningconcurrency {
def log(msg: String): Unit =
println(s"${Thread.currentThread.getName}: $msg")
}

We will use the log method in the examples throughout this book to trace how the
concurrent programs are executed.
This concludes our quick overview of important Scala features. If you would like to
obtain a deeper knowledge about any of these language constructs, we suggest that
you check out one of the introductory books on sequential programming in Scala.

[ 23 ]

For More Information:


www.packtpub.com/application-development/learning-concurrentprogramming-scala

Introduction

Summary
In this chapter, we studied what concurrent programming is and why Scala is a good
language for concurrency. We gave a brief overview of what you will learn in this
book, and how the book is organized. Finally, we stated some Scala preliminaries
necessary for understanding the various concurrency topics in the subsequent
chapters. If you would like to learn more about sequential Scala programming, we
suggest that you read the book Programming in Scala, Martin Odersky, Lex Spoon, and
Bill Venners, Artima Inc.
In the next chapter, we will start with the fundamentals of concurrent programming
on the JVM. We will introduce the basic concepts in concurrent programming,
present the low-level concurrency utilities available on the JVM, and learn about
the Java Memory Model.

Exercises
The following exercises are designed to test your knowledge of the Scala
programming language. They cover the content presented in this chapter, along
with some additional Scala features. The last two exercises contrast the difference
between concurrent and distributed programming, as defined in this chapter. You
should solve them by sketching out a pseudocode solution, rather than a complete
Scala program.
1. Implement a compose method with the following signature:
def compose[A, B, C](g: B => C, f: A => B): A => C = ???

This method must return a function h, which is the composition of the


functions f and g.
2. Implement a fuse method with the following signature:
def fuse[A, B](a: Option[A], b: Option[B]): Option[(A, B)] = ???

The resulting Option object should contain a tuple of values from the
Option objects a and b, given that both a and b are non-empty. Use
for-comprehensions.
3. Implement a check method, which takes a set of values of the type T and
a function of the type T => Boolean:
def check[T](xs: Seq[T])(pred: T => Boolean): Boolean = ???

[ 24 ]

For More Information:


www.packtpub.com/application-development/learning-concurrentprogramming-scala

Chapter 1

The method must return true if and only if the pred function returns true
for all the values in xs without throwing an exception. Use the check
method as follows:
check(0 until 10)(40 / _ > 0)

The check method has a curried definition: instead of just one


parameter list, it has two of them. Curried definitions allow
a nicer syntax when calling the function, but are otherwise
semantically equivalent to single-parameter list definitions.

4. Modify the Pair class from this chapter so that it can be used in a
pattern match.
If you haven't already, familiarize yourself with pattern
matching in Scala.

5. Implement a permutations function, which, given a string, returns a


sequence of strings that are lexicographic permutations of the input string:
def permutations(x: String): Seq[String]

6. Consider yourself and three of your colleagues working in an office divided


into cubicles. You cannot see each other, and you are not allowed to verbally
communicate, as that might disturb other workers. Instead, you can throw
pieces of paper with short messages at each other. Since you are confined in
a cubicle, neither of you can tell if the message has reached its destination.
At any point, you or one of your colleagues may be called to the boss's office
and kept there indefinitely. Design an algorithm in which you and your
colleagues can decide when to meet at the local bar. With the exception of
the one among you who was called to the boss's office, all of you have to
decide on the same time. What if some of the paper pieces can arbitrarily
miss the target cubicle?
7. Imagine that in the previous exercise, you and your colleagues also have a
whiteboard in the hall next to the office. Each one of you can occasionally
pass through the hall and write something on the whiteboard, but there
is no guarantee that either of you will be in the hall at the same time.
Solve the problem from the previous exercise, this time using the whiteboard.

[ 25 ]

For More Information:


www.packtpub.com/application-development/learning-concurrentprogramming-scala

Where to buy this book


You can buy Learning Concurrent Programming in Scala from the Packt Publishing
website:
.
Free shipping to the US, UK, Europe and selected Asian countries. For more information, please
read our shipping policy.

Alternatively, you can buy the book from Amazon, BN.com, Computer Manuals and
most internet book retailers.

www.PacktPub.com

For More Information:


www.packtpub.com/application-development/learning-concurrentprogramming-scala

You might also like