Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Scala Functional Programming Patterns
Scala Functional Programming Patterns

Scala Functional Programming Patterns: Grok and perform effective functional programming in Scala

eBook
€22.99 €32.99
Paperback
€41.99
Subscription
Free Trial
Renews at €18.99p/m

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Table of content icon View table of contents Preview book icon Preview Book

Scala Functional Programming Patterns

Chapter 1. Grokking the Functional Way

Before we start learning Scala, let's first understand what functional programming (FP) is. You may have used a spreadsheet while working. In a spreadsheet, there is a bunch of equations and we enter values in the given cells for these equations. We get the answers through these equations. When you enter the same values again, you get the same answer and there are no fallouts.

At the core of FP is composition. Looking at a software system made up of parts, we build bigger parts by composing smaller parts. If you think about it, most complex systems are composed of parts, which in turn are composed of smaller parts. Functional languages give us the means to make this composition. One of the prominent functional languages that can be used for FP is Scala.

Scala in Italian means a staircase. If you look at the language's logo, you will see it's a staircase. The language acts as a staircase through which we can ascend and become better at programming. Scala also refers to the very many techniques that we can use to control the complexity of large-scale systems.

We will begin to learn Scala by looking at abstractions. We will see why abstractions are good and how Scala helps us to be abstract. Scala code is concise and expressive. A lot of the concise expression is due to functions. Functions are an important pillar of functional programming. In this chapter, we will look at pure and impure functions. Reducing the number of moving parts to be used is an effective technique to control programming complexity. Immutability is another pillar of FP that helps us here. To see all this in effect, we will take a problem example and implement the solution in Java. Then, we will solve the problem using Scala. Looking at a few Scala one-liners will help us to get started with READ/EVALUATE/PRINT LOOP (REPL). We will use Scala REPL extensively throughout the entire book.

Finally, we will look at idioms and patterns. Traditional patterns in Scala look very different from their Java counterparts. We will briefly look at the command and strategy of Scala and see how functions are used to pass algorithms around.

Welcome to the Scala fun ride!

Abstractions

What do we mean by abstractions? Why are they important? To understand this, we will compare two approaches. First, the "go to the wall and pull at one of the wooden panels fitted into the rectangular hole" approach versus the "open the door, please" approach.

A door is an abstraction. We really don't care whether it is made of wood or some other material, or what type of a lock it has, or any other details. The details are important, but not always. If we worry about the details always, we would quickly get bogged down, and all the communication would effectively come to a halt.

A table is an abstraction, so is a chair, and so is a house. I hope you get the drift. We want to be selectively ignorant of the details at times, and selective ignorance is abstraction.

Now, you may ask why does it matter to us programmers? The reason is that it gets things done in a compact manner.

For example, let's look at the following Scala code, which is used to count the frequency of characters in a string:

scala> "hello world".toList.filter(_.isLetter).groupBy(x => x).map { y =>
     |   y._1 -> y._2.size
     | }
res1: scala.collection.immutable.Map[Char,Int] = Map(e -> 1, l -> 3, h -> 1, r -> 1, w -> 1, o -> 2, d -> 1)

Isn't it compact?

On the Urban Dictionary website, http://www.urbandictionary.com/define.php?term=cutie, the term "cutie" is defined as compact beauty—the kind you just want to put in your pocket and keep beside you forever.

I was bowled over when I first saw it all. It is concise, short, packs a punch, and is elegant. The Type Less Do More philosophy. Gets a lot done with less...

Note

To run the code snippet, fire up the Scala REPL. This looks a lot like a command console, a prompt waiting for you to key in Scala code. In a command terminal, typing just Scala fires up the REPL:

~> scala

It will give the following output:

Welcome to Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_25).

You can type in expressions to have them evaluated and type help for more information. Let's try the following simple one line commands:

scala> 1 + 1
res2: Int = 2
scala> "hello".length
res4: Int = 5

For me, Scala brought the thrill back to programming... You can do a great deal by writing a few lines of code—less is more...

Scala gives you many tools, so the code is abstract and reusable...

Concise expression

You always want to be able to concisely express yourself. Let's try the following command to create a string:

scala> val list = List("One", "two", "three", "Four", "five")
list: List[String] = List(One, two, three, Four, five)

We have created a list of strings. Note that we neither had to specify the type of the list for this, nor any new keyword. We just expressed that we wanted a list assigned to a read-only variable.

Code reviews do a lot of good to a code base. I keep looking for places where I can replace a variable assignment with variable initialization. Refer to the following URL for an example: http://www.refactoring.com/catalog/replaceAssignmentWithInitialization.html.

Scala helps us with the val keyword. With the use of this keyword, we can establish the following:

  • The initial value of variable must be specified (it is impossible for the variable to remain uninitialized).
  • The value of variable cannot ever be changed again (there is one less moving part).

Why is this so important? A system with less moving parts is easier to understand and explain. You will be knowing that Google is well known for its less-moving-parts software. Let's try the following command to check for the uppercase in these characters:

scala> def hasUpperCaseChar(s: String) = s.exists(_.isUpper)
hasLowerCaseChar: (s: String)Boolean

What does s.exists(_.isUpper) do? In this code, I have a string and I am checking whether it has one or more uppercase characters.

Note that I need to look at each character of the string to arrive at an answer as output. However, I did not have to split the string into its constituent characters and then work on each character.

I am just expressing the algorithm. The algorithm involves iterating all characters. However, I did not write a loop. Instead, I expressed what I meant, concisely. Scala's strings are collections of characters. We can try the following command to make use of a filter method:

scala> list filter (hasUpperCaseChar)
res2: List[String] = List(One, Four)

Just like a string, List is again a collection, in this case, of strings. I used a list method, filter, to weed out elements that did not satisfy the predicate.

If we were to write this imperatively, we would need a nested loop (a loop within another loop). The first loop would take each string, and the inner loop would work on each character of the string. We would need a list to collect the matching elements.

Instead of lists, we just declared what we wanted to happen. However, at some point of time in the code the looping needs to happen! It does happen indeed, but behind the scenes and in the filter method.

The filter method is a higher order function that receives the hasUpperCaseChar function.

Let's say, in addition to this method, we want only those string elements that have a length greater than 3:

scala> list filter (x => hasLowerCaseChar(x) && x.size > 3)
res1: List[String] = List(Four)

We are again executing the algorithm; however, with a different match criteria. We are passing a function in the form of a function literal. Each element in the list is bound to x, and we run a check on x.

The preceding form of expression allows us to concisely express our intent. A large part of this flexibility comes from the idea of sending small computations around that are expressible without much ado. Welcome to functions!

Functions

Functional programming includes a lot about functions. There are different kinds of functions in programming, for example, pure functions. A pure function depends only on its input to compute the output. Let's try the following example to make use of functions:

scala> val addThem = (x: Int, y: Int) => x + y + 1
addThem: (Int, Int) => Int = <function2>
scala> addThem(3,4)
res2: Int = 8

As long as the function lives, it will always give the result 8 given the input (3,4).Take a look at the following example of a pure function:

Functions

Figure 1.1: Pure functions

The functions worked on the input and produced the output, without changing any state. What does the phrase "did not change any state" mean? Here is an example of a not-so-pure function:

scala> var p = 1
p: Int = 1
scala> val addP = (x: Int, y: Int) => {
     | p += 1
     | x + y + p
     | }
addP: (Int, Int) => Int = <function2>

scala> addP(3, 4)
res4: Int = 9
scala> addP(3, 4)
res5: Int = 10

This addP function changes the world—this means that it affects its surroundings. In this case, the variable p. Here is the diagrammatic representation for the preceding code:

Functions

Figure 1.2 :An impure function

Comparing addThem and addP, which of the two is clearer to reason about? Remember that while debugging, we look for the trouble spot, and we wish to find it quickly. Once found, we can fix the problem quickly and keep things moving.

For the pure function, we can take a paper and pen, and since we know that it is side effects free, we can write the following:

addThem(3, 4) = 8
             addThem(1,1) = 3

For small numbers, we can do the function computation in our heads. We can even replace the function call with the value:

scala> addThem(1,1) + addThem(3,4)
res10: Int = 11
scala> 3 + 8
res11: Int = 11  

Both the preceding expressions are equivalent. When we replace the function, we deal with referentially transparent expressions. If the function is a long running one, we could call it just once and cache the results. The cached results would be used for the second and subsequent calls.

The addP function, on the other hand, is referentially opaque.

Immutable

Each one of us has a name. Let's keep this simple—a first and last name. My first name is Atul and my last name is Khot. If someone suddenly called me by the name Prakash, things won't work!

Keeping aside cases such as writers taking a pen name (that is, Plum for PG Wodehouse), commonly each one of us has a standard, official name. We simply don't want parts of it changed to willy nilly. Let's try the following example:

scala> case class FullName(firstName: String, lastName: String)
defined class FullName
scala> val name = FullName("Bertie", "Wooster")
name: FullName = FullName(Bertie,Wooster)

scala> name.firstName = "Mrs. Bertie"
<console>:13: error: reassignment to val
       name.firstName = "Albert"

Scala stopped us changing the code of Woosters!! It just saved Bertie from getting a wife!

In case you need a break and some light relief, Google The Code of the Woosters!

Once a case class instance is created, it is sealed. You can read it, but you cannot change it:

scala> name.firstName
res12: String = Bertie
scala> name.lastName
res13: String = Wooster

You can even look at the signified version of the instance that the compiler writes for you:

scala> name
res14: FullName = FullName(Bertie,Wooster)

And you can destructure it using pattern matching. Immutability just reduces the moving parts and helps us to restore sanity. This is a boon when threads enter the picture.

Referential transparency

To understand referential transparency, let's first consider the following description:

Let me tell you a bit about India's capital, New Delhi. The Indian capital houses the Indian Parliament. The Indian capital is also home to Gali Paranthe Wali, where you get to eat the famous parathas.

We can also say the following instead:

Let me tell you a bit about India's capital, New Delhi. New Delhi houses the Indian Parliament. New Delhi is also home to Gali Paranthe Wali, where you get to eat the famous parathas.

Here, we substituted New Delhi with the Indian capital, but the meaning did not change. This is how we would generally express ourselves.

The description is referentially transparent with the following commands:

scala> def f1(x: Int, y: Int) = x * y
f1: (x: Int, y: Int)Int

scala> def f(x: Int, y: Int, p: Int, q: Int)= x * y + p * q
f: (x: Int, y: Int, p: Int, q: Int)Int

scala> f(2, 3, 4, 5)
res0: Int = 26

If we rewrite the f method as follows, the meaning won't change:

scala> def f(x: Int, y: Int, p: Int, q: Int)= f1(x, y) + f1(p, q)
f: (x: Int, y: Int, p: Int, q: Int)Int

The f1 method just depends upon its arguments, that is, it is pure.

Which method is not referentially transparent? Before we look at an example, let's look at Scala's ListBuffer function:

scala> import scala.collection.mutable.ListBuffer
import scala.collection.mutable.ListBuffer

The ListBuffer is a mutable collection. You can append a value to the buffer and modify it in place:

scala> val v = ListBuffer.empty[String]
v: scala.collection.mutable.ListBuffer[String] = ListBuffer()

scala> v += "hello"
res10: v.type = ListBuffer(hello)

scala> v
res11: scala.collection.mutable.ListBuffer[String] = ListBuffer(hello)

scala> v += "world"
res12: v.type = ListBuffer(hello, world)

scala> v
res13: scala.collection.mutable.ListBuffer[String] = ListBuffer(hello, world)

Armed with this knowledge, let's now look at the following command:

scala> val lb = ListBuffer(1, 2)
lb: scala.collection.mutable.ListBuffer[Int] = ListBuffer(1, 2)

scala> val x = lb += 9
x: lb.type = ListBuffer(1, 2, 9)
scala> println(x.mkString("-"))
1-2-9
scala> println(x.mkString("-"))
1-2-9

However, by substituting x with the expression (lb += 9), we get the following:

scala> println((lb += 9).mkString("-")) // 1 
1-2-9-9
scala> println((lb += 9).mkString("-")) // 2
1-2-9-9-9

This substitution gave us different results. The += method of ListBuffer is not a pure function as there is a side effect that occurred. The value of the lb variable at 1 and 2 is not the same.

The problem – grouping continuous integers

A while back, I wanted a simple and elegant way to solve the following problem:

Given: A sorted list of numbers

When: We group these numbers

Then: Each number in a group is higher by one than its predecessor. So, let's be good and write a few tests first:

 @Test
 public void testFourGroup() {
  List<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5, 9, 11, 20, 21, 22);
  List<List<Integer>> groups = groupThem.groupThem(list);
  assertThat(groups.size(), equalTo(4));
  assertThat(groups.get(0), contains(1, 2, 3, 4, 5));
  assertThat(groups.get(1), contains(9));
  assertThat(groups.get(2), contains(11));
  assertThat(groups.get(3), contains(20, 21, 22));
 }
 @Test
 public void testNoGroup() {
  List<Integer> emptyList = Lists.newArrayList();
  List<List<Integer>> groups = groupThem.groupThem(emptyList,
    new MyPredicate());
  assertThat(groups, emptyIterable());
}
 @Test
 public void testOnlyOneGroup() {
  List<Integer> list = Lists.newArrayList(1);
  List<List<Integer>> groups = groupThem.groupThem(list,new MyPredicate());
  assertThat(groups.size(), equalTo(1));
  assertThat(groups.get(0), contains(1));
 }

We will make use of the excellent Hamcrest matchers (and the excellent Guava library) to help us express succinctly what we want our code to do.

Java code

You know the drill! Let's roll up our sleeves and dish out some code. The following looks pretty good:

 public List<List<Integer>> groupThem(final List<Integer> list) {
  final List<Integer> inputList = Colletions.unmodifiableList(list);
  final List<List<Integer>> result = Lists.newArrayList();
  int i = 0;
   while( i < inputlist.size()){
   i = pickUpNextGroup(i, inputList, result); // i must progress
  }
 return result;
 }

 private int pickUpNextGroup(final int start, final List<Integer> inputList,
   final List<List<Integer>> result) {
  Validate.isTrue(!inputList.isEmpty(),
    "Input list should have at least one element");
  Validate.isTrue(start <= inputList.size(), "Invalid start index");

  final List<Integer> group = Lists.newArrayList();
  
  int currElem = inputList.get(start );
  group.add(currElem); // We will have at least one element in the group

  int next = start + 1; // next index may be out of range

  while (next < inputList.size()) {
   final int nextElem = inputList.get(next); // next is in range
   if (nextElem - currElem == 1) { // grouping condition
    group.add(nextElem);
    currElem = nextElem; // setup for next iteration
   } else {
    break; // this group is done
   }
   ++next;
  }
  result.add(group); // add the group to result list
  Validate.isTrue(next > start); // make sure we keep moving
  return next; // next index to start iterating from
                // could be past the last valid index
 }

This code has a lot of subtlety. We use the Apache commons 3 validation API for asserting the invariants. Download this book's source code to check out the unit test.

We are using the excellent Guava library to work with lists. Note the ease of this library, with which we can create and populate the list in one line. Refer to https://code.google.com/p/guava-libraries/wiki/CollectionUtilitiesExplained for more details.

We are careful to first make the input list an unmodifiable list—to protect ourselves from stepping on our toes... We also need to carefully arrange the iteration to make sure that it eventually terminates and we do not accidentally access a non-existent list index (try to say it without gulping).

Going scalaish

Remember the sermon on being abstract? Our Java code is dealing with a lot of higher level and lower level details—all at the same time... We really don't want to do that; we wish to selectively ignore the details... We really don't want to deal with all the corner cases of iteration—the Java code is worried stiff about looking at two consecutive elements and the corner cases.

What if this was somehow handled for us so we can focus on the business at hand? Let's take a look at the following example:

def groupNumbers(list: List[Int]) = {
  def groupThem(lst: List[Int], acc: List[Int]): List[List[Int]] = lst match {
    case Nil => acc.reverse :: Nil
    case x :: xs =>
      acc match {
        case Nil => groupThem(xs, x :: acc)
        case y :: ys if (x - y == 1) =>
          
            
         
      case _ =>
            acc.reverse :: groupThem(xs, x :: List())
      }
  }
  groupThem(list, List())
}
groupNumbers(x)  

Thinking recursively...

This version looks a lot better—doesn't it? We use features such as nested functions and recursion and get stuff such as immutability for free... A list in Scala is immutable.In Java, we need to work a bit more to make things immutable. In Scala, it is the other way around. You need to go a little further to bring in mutability... We also use something called persistent data structures that have nothing to do with databases here. We will look at it in detail in a while...

However, a bit better version follows—meaning a tail-recursive version. Take a look at the following example of it:

def groupNumbers(list: List[Int])(f: (Int, Int) => Boolean) : List[List[Int]] = {
  @tailrec
  def groupThem(lst: List[Int], result: List[List[Int]], acc: List[Int]): List[List[Int]] = lst match {
    case Nil => acc.reverse :: result
    case x :: xs =>
      acc match {
        case Nil => groupThem(xs, result, x :: acc)
        case y :: ys if (x - y == 1) =>
          
            groupThem(xs, result, x :: acc)
        
      case _ => 
            groupThem(xs, acc.reverse :: result, x :: List())
      }
  }
  val r = groupThem(list, List(), List())
  r.reverse
}

The @tailrec function does some good to our code. This is an annotation that we put on a method. We use it to make sure that the method will be compiled with tail call optimization (TCO). TCO converts the recursive form into a loop.

If the Scala compiler cannot apply TCO, it flags an error. Recursion and TCO are covered in detail in Chapter 3, Recursion and Chasing Your Own Tail.

Now, having set the stage—let's look at the reusability feature...

Reusability – the commonality/variability analysis

Instead of a fixed grouping criteria, could we make the Java version more dynamic? Instead of the expressing the condition directly in the code, we could wrap up the condition as a predicate:

if (nextElem - currElem == 1) { // grouping condition	

A predicate is a function that returns a Boolean value. It should take two numbers and tell whether the predicate is true or false?

Now there could be multiple predicates. For example, we might want to find elements that differ by 2 or 3 numbers. We can define an interface as follows:

public interface Predicate {
        boolean apply(int nextElem, int currElem);
}

public class MyPredicate implements Predicate {

    public boolean apply(int nextElem, int currElem) {
        return nextElem - currElem == 1;
    }
}

Why would we do this? We would do this for two reasons:

  • We would want to reuse the algorithm correctly and pick up two consecutive elements. This algorithm would handle all corner cases as in the previous cases.
  • The actual grouping criteria in our case is nextElem – currElem == 1, but we can reuse the previous code to regroup the numbers using another criteria.

Here is how grouping would look; I am just showing the changed code:

public List<List<Integer>> groupThem(List<Integer> list, Predicate myPredicate) {
    ...
        while (int i = 0; i < inputList.size();) {
            i = pickUpNextGroup(i, inputList, myPredicate, result); // i must
            // progress
            ...
        }
}

private int pickUpNextGroup(int start, List<Integer> inputList, Predicate myPredicate,
        List<List<Integer>> result) {
    ...
    final int nextElem = inputList.get(next); // next is in range
    // if (nextElem - currElem == 1) { // grouping condition
    if (myPredicate.apply(nextElem, currElem)) { // grouping condition
        group.add(nextElem);
    ...
    }
}

It is some work to define and use the predicate. Scala makes expressing this variability pretty easy, as we can use functions. Just pass on your criteria as a function and you are good to go:

def groupNumbers(list: List[Int])(f: (Int, Int) => Boolean) :  // 1  = {
  def groupThem(lst: List[Int], acc: List[Int]): List[List[Int]] = lst match {
    case Nil => acc.reverse :: Nil
    case x :: xs =>
      acc match {
        case Nil => groupThem(xs, x :: acc)
        case y :: ys if (f(y, x)) =>
              // 2
            groupThem(xs, x :: acc)
          
    case _ =>
            acc.reverse :: groupThem(xs, x :: List())
      }
  }
  groupThem(list, List())
}
val p = groupNumbers(x) _ // 3
p((x, y) => y - x == 1)   // 4
p((x, y) => y - x == 2)   // 5

In 1, we use the function - (f: (Int, Int) => Boolean).

Note

The f: (Int, Int) => Boolean syntax means that f is a function parameter. The function takes two Int params and returns Boolean.

Here is a quick REPL session to understand this better:

scala> val x : (Int, Int) => Boolean = (x: Int, y: Int) => x > y
x: (Int, Int) => Boolean = <function2>
scala> x(3, 4)
res0: Boolean = false
scala> x(3, 2)
res1: Boolean = true
scala> :t x
(Int, Int) => Boolean

We are using the t feature of the REPL to look at the type of x.

This is a function—a bit of code we can pass around—that corresponds to the previous Java predicate snippet. It is a function that takes two integers and returns a Boolean.

(A function is in fact a class that mixes in a trait, function2 in our case).

At 2, we use it. Now comes the fun part.

At 3, we hold on to everything else except the function. And at 4 and 5, we just pass different functions. It would be more correct to say that we use function literals. lo and behold —we get the answers right.

This code also shows some currying and partially applied functions in action… We cover both of these features in Chapter 6, Currying Favors with Your code.

The one-liner shockers

Have you heard this phrase anytime: it is just a one-liner! You see all the work done in a single line of code, it seems almost magical. The Unix shell thrives on these one-liners. For example:

       seq 1 100 | paste -s -d '*' | bc

Phew! This single command line generates a sequence of numbers, 1 to 100, generates a multiplication expression from these, and feeds the same to bca calculator that does the actual multiplication.

Scala has a legion of these. Here is one applied to our problem by using scalaz library.

Note

To try the following snippet, you need to install the scalaz library. It is not part of the Scala standard library. Here are a few simple instructions to install it.

Create a directory of your choice and switch to it. Next, download and install the Simple Build Tool (sbt) from http://www.scala-sbt.org/download.html.

/Users/Atulkhot/TryScalaz> sbt
[info] Set current project to tryscalaz (in build file:/Users/Atulkhot/TryScalaz/)
> set scalaVersion := "2.11.7"
… // output elided
> set libraryDependencies += "org.scalaz" %% "scalaz-core" % "7.1.0"
… // output elided
> console

Now the following snippet should work after installing the scalaz library:

scala> import scalaz.syntax.std.list._
import scalaz.syntax.std.list._
scala> List(1, 2, 3, 4, 6, 8, 9) groupWhen ((x,y) => y - x == 1)
res3: List[scalaz.NonEmptyList[Int]] = List(NonEmptyList(1, 2, 3, 4), NonEmptyList(6), NonEmptyList(8, 9))

Using functions the solution is just a one-liner:

scala> List(1, 3, 4, 6, 8, 9) groupWhen ((x,y) => y - x == 2)
res4: List[scalaz.NonEmptyList[Int]] = List(NonEmptyList(1, 3), NonEmptyList(4, 6, 8), NonEmptyList(9))

So we are just not writing any of the supporting code—just stating our criteria for grouping.

You can read more about Scalaz at http://eed3si9n.com/learning-scalaz/.

Scala idioms

When do we know a language? In English, when we say a penny for your thoughts, we are using an idiom. We can express ourselves more succinctly and natively using these. Beating around the bush is another one. If we pick up enough of these and hurl them around at times, this will makes us fluent.

It is almost the same with programming languages. You see a construct time and again and make use of notable features of a specific programming language. Here is a sample of idioms from a few prominent languages.

For example, here is an idiomatic Scala way to sum up two lists of numbers:

scala> val d1 = List(1, 2, 3, 4, 5)
d1: List[Int] = List(1, 2, 3, 4, 5)

scala> val d2 = List(11, 22, 33, 44, 55)
d2: List[Int] = List(11, 22, 33, 44, 55)

scala> (d1, d2).zipped map (_ + _)
res0: List[Int] = List(12, 24, 36, 48, 60)

We could do this in a roundabout way; however, note that your Scala colleagues would quickly comprehend what is happening. Try the following command:

scala> (1 to 100).map( _ * 2 ).filter(x => x % 3 == 0 && x % 4 == 0 && x % 5 == 0)
res2: scala.collection.immutable.IndexedSeq[Int] = Vector(60, 120, 180)

For numbers from 1 to 100, we multiply each number by 2. We select those numbers that are divisible by 3, 4, and 5.

Here we are chaining method calls together. Each method returns a new value. The input is left unmodified. The intermediate values are threaded from call to call.

We could also write the preceding command as follows

scala> val l1 = 1 to 100
… // output elided
scala> val l2 = l1.map(_ * 2)
 … // output elided
scala> val l3 = l2.filter(x => x % 3 == 0 && x % 4 == 0 && x % 5 == 0)
l3: scala.collection.immutable.IndexedSeq[Int] = Vector(60, 120, 180)

However, the fluent API style is more idiomatic.

Note

You can learn more about fluent interfaces at http://www.martinfowler.com/bliki/FluentInterface.html.

People relate easily to idiomatic code. When we learn and use various Scala idioms, we will write code in the Scala way.

Patterns and those aha! moments

Patterns have more to do with a software design such as how to compose things together, the kind of design template to be used, and so on. They are a lot more about interactions between classes and objects. Patterns are design recipes, and they illustrate a solution to a recurring design problem. However, idioms are largely specific to a language and patterns are more general and at a higher level. Patterns are also mostly language independent.

You can (and usually do) implement the same design patterns in the language you are working with.

The command design pattern

The command design pattern encapsulates an object. It allows you to invoke a method on the object at a later point. For example, we are used to the following code line:

Given a Java object:

          a.someMethod(arg1, arg2);
          a.method1(arg1, arg2);
          a.method2(arg3);

We expect the call a.method1 to complete before the a.method2 call starts. On the other hand, consider a real life situation.

Let's say you go to a restaurant, sit at a table, and order food. The waiter scribbles down the order on a piece of paper. This piece of paper then goes to the kitchen, someone cooks the food, and the food is served. It makes sense to prepare food for someone who ordered earlier, so your order is queued.

In the preceding paragraph, the piece of paper holds the details of your order. This is the command object. The preceding description also talks about a queue where the someone who cooks is the invoker—he puts things in motion as per your command. Add the undo() functionality and you have the essence of the command design pattern. Database transactions need to undo the commands on failure—the rollback semantics, for example.

Here is a simple first cut as example:

def command(i : Int) = println(s"---$i---")
def invokeIt(f : Int => Unit) = f(1)
invokeIt(command)

Note

The def method gets converted to a function. This is called an ETA expansion. We will soon be looking at the details.

This is a bit unpalatable though. I can possibly pass any function whatsoever and possibly wreak havoc. So, to constrain the things we can possibly pass on to the invoker, we take a bit of help from the compiler by typing the following commands:

scala> case class Command(f: Int => Unit)
defined class Command

scala> def invokeIt(i: Int, c: Command) = c.f(i)
invokeIt: (i: Int, c: Command)Unit

scala> def cmd1 = Command(x => println(s"**${x}**"))
cmd1: Command

scala> def cmd2 = Command(x => println(s"++++${x}++++"))
cmd2: Command

scala> invokeIt(3, cmd1)
**3**

scala> invokeIt(5, cmd2)
++++5++++

It is so terse.

The strategy design pattern

Strategy helps us to define a set of algorithms, encapsulates each step, and selects one as appropriate.

Oh boy! Here it is. We surely have used the java.util.Comparator strategy interface at times that allows us to vary the compare algorithm as we see fit so we can sort arrays at will. Let's try the following example:

       Integer[] arr = new Integer[] { 1, 3, 2, 4 };
  Comparator<Integer> comparator = new Comparator<Integer>() {
   @Override
   public int compare(Integer x, Integer y) {
    return Integer.compare(y, x); // the strategy algorithm –// for reverse sorting
    }
  };
  Arrays.sort(arr, comparator);
  System.out.println(Arrays.toString(arr));

Scala makes it a breeze by using these strategy... Type the following command to sort an array:

scala> List(3, 7, 5, 2).sortWith(_ < _)
res0: List[Int] = List(2, 3, 5, 7)

Passing algorithms around

We need this ability to plug in an algorithm as needed. When we start applying a strategy, we really try to apply the Open/Closed principle (OCP). We don't touch the sort algorithm internals, that is, the sort implementation is closed for modification. However, by passing in a comparator, we can use the algorithm to sort objects of various classes that are open for extension.

This open for extension feature is realized very easily in Scala, as it allows us to pass functions around.

Here's another code snippet as an example of passing functions:

def addThem(a: Int, b: Int) = a + b // algorithm 1
def subtractThem(a: Int, b: Int) = a - b // algorithm 2
def multiplyThem(a: Int, b: Int) = a * b // algorithm 3

def execute(f: (Int, Int) => Int, x: Int, y: Int) = f(x, y)

println("Add: " + execute(addThem, 3, 4))
println("Subtract: " + execute(subtractThem, 3, 4))
println("Multiply: " + execute(multiplyThem, 3, 4))

Here, these various strategy algorithms are functions—no boilerplate. Imagine writing this in Java. This code is possible because in Scala, we can pass functions around as objects. Furthermore, we can use a method where a function is expected:

val divideThem = (x: Int, y: Int) => x / y
println("Divide: " + execute(divideThem, 11, 5))

Scala's functions are first-class objects, meaning they can be sent to a method and returned from a method, just like a number or string. The ability to pass functions to other functions is a very powerful concept. It is one of the major pillars of FP, as we will soon see.

Summary

Scala is expressive and rich with tools that help us to eliminate boilerplates. It allows us to concisely express the intention of programming. Functions help us reuse the common facilities, freeing us from coding them every time.

Pure functions are simpler to reason about, as there are lot less moving parts. We can think of them in terms of referential transparency. Impure functions are hard to reason with. We saw how making things immutable also helps in reducing these moving parts.

Idioms are what make us use a language effectively. This is true for programming languages. Scala is a feature-rich functional programming language. We got a bird's eye view of a few Scala features, such as recursion and functions.

Design patterns are a programmer's vocabulary. Scala gives us a fresh perspective of patterns, and we saw how the use of functions makes using design patterns so very easy in Scala.

We implemented the solution to a problem in Java and Scala. We saw how succinct and expressive the Scala code is compared to its Java counterpart.

We got our feet wet in the Scala land. Let's look at these features in detail and see how Scala makes programming cool and fun again. We will start with singleton and factories. Get, set, and go!

Left arrow icon Right arrow icon

Key benefits

  • Understand functional programming patterns by comparing them with the traditional object-oriented design patterns
  • Write robust, safer, and better code using the declarative programming paradigm
  • An illustrative guide for programmers to create functional programming patterns with Scala

Description

Scala is used to construct elegant class hierarchies for maximum code reuse and extensibility and to implement their behavior using higher-order functions. Its functional programming (FP) features are a boon to help you design “easy to reason about” systems to control the growing software complexities. Knowing how and where to apply the many Scala techniques is challenging. Looking at Scala best practices in the context of what you already know helps you grasp these concepts quickly, and helps you see where and why to use them. This book begins with the rationale behind patterns to help you understand where and why each pattern is applied. You will discover what tail recursion brings to your table and will get an understanding of how to create solutions without mutations. We then explain the concept of memorization and infinite sequences for on-demand computation. Further, the book takes you through Scala’s stackable traits and dependency injection, a popular technique to produce loosely-coupled software systems. You will also explore how to currying favors to your code and how to simplify it by de-construction via pattern matching. We also show you how to do pipeline transformations using higher order functions such as the pipes and filters pattern. Then we guide you through the increasing importance of concurrent programming and the pitfalls of traditional code concurrency. Lastly, the book takes a paradigm shift to show you the different techniques that functional programming brings to your plate. This book is an invaluable source to help you understand and perform functional programming and solve common programming problems using Scala’s programming patterns.

Who is this book for?

If you have done Java programming before and have a basic knowledge of Scala and its syntax, then this book is an ideal choice to help you to understand the context, the traditional design pattern applicable, and the Scala way. Having previous knowledge of design patterns will help, though it is not strictly necessary.

What you will learn

  • Get to know about functional programming and the value Scala s FP idioms bring to the table
  • Solve day-to-day programming problems using functional programming idioms
  • Cut down the boiler-plate and express patterns simply and elegantly using Scala s concise syntax
  • Tame system complexity by reducing the moving parts
  • Write easier to reason about concurrent code using the actor paradigm and the Akka library
  • Apply recursive thinking and understand how to create solutions without mutation
  • Reuse existing code to compose new behavior
  • Combine the object-oriented and functional programming approaches for effective programming using Scala
Estimated delivery fee Deliver to Netherlands

Premium delivery 7 - 10 business days

€17.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Dec 29, 2015
Length: 298 pages
Edition : 1st
Language : English
ISBN-13 : 9781783985845
Category :
Languages :

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Estimated delivery fee Deliver to Netherlands

Premium delivery 7 - 10 business days

€17.95
(Includes tracking information)

Product Details

Publication date : Dec 29, 2015
Length: 298 pages
Edition : 1st
Language : English
ISBN-13 : 9781783985845
Category :
Languages :

Packt Subscriptions

See our plans and pricing
Modal Close icon
€18.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
€189.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts
€264.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total 134.97
Scala Functional Programming Patterns
€41.99
Scala Design Patterns
€45.99
Scala for Data Science
€46.99
Total 134.97 Stars icon

Table of Contents

12 Chapters
1. Grokking the Functional Way Chevron down icon Chevron up icon
2. Singletons, Factories, and Builders Chevron down icon Chevron up icon
3. Recursion and Chasing your Own Tail Chevron down icon Chevron up icon
4. Lazy Sequences – Being Lazy, Being Good Chevron down icon Chevron up icon
5. Taming Multiple Inheritance with Traits Chevron down icon Chevron up icon
6. Currying Favors with Your Code Chevron down icon Chevron up icon
7. Of Visitors and Chains of Responsibilities Chevron down icon Chevron up icon
8. Traversals – Mapping/Filtering/Folding/Reducing Chevron down icon Chevron up icon
9. Higher Order Functions Chevron down icon Chevron up icon
10. Actors and Message Passing Chevron down icon Chevron up icon
11. It's a Paradigm Shift Chevron down icon Chevron up icon
Index Chevron down icon Chevron up icon

Customer reviews

Rating distribution
Full star icon Full star icon Full star icon Half star icon Empty star icon 3.5
(2 Ratings)
5 star 0%
4 star 50%
3 star 50%
2 star 0%
1 star 0%
cust: Feb 05, 2024
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
-gets you up to speed in knowning basics in fp world
Amazon Verified review Amazon
Mark V. Jan 14, 2016
Full star icon Full star icon Full star icon Empty star icon Empty star icon 3
While this book introduces functional programming principles, it does so without any real plan. Deconstruction and pattern matching are mixed in a chapter on recursion. The book does pick up some pace after the first half, where it does a decent job of introducing flatMap, map, monads and monoids.This book contains a lot of Java (namely unit tests) along with Scala. I feel like the tests should have been written in Scala too, this is a Scala book after all.What annoyed me most about this book, were the links to more information. Instead of explaining the concepts briefly, there are some 10 links provided, such as "Some expensive objects may need to be lazy-initialized. Refer to http://martinfowler.com/bliki/LazyInitialization.html for a very nice introduction to lazy initialization." This makes the book feel unfinished.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact customercare@packt.com with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at customercare@packt.com using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on customercare@packt.com with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on customercare@packt.com within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on customercare@packt.com who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on customercare@packt.com within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela