Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
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
Mex$631.99 Mex$902.99
Paperback
Mex$1128.99
Subscription
Free Trial

What do you get with a Packt Subscription?

Free for first 7 days. $19.99 p/m after that. Cancel any time!
Product feature icon Unlimited ad-free access to the largest independent learning library in tech. Access this title and thousands more!
Product feature icon 50+ new titles added per month, including many first-to-market concepts and exclusive early access to books as they are being written.
Product feature icon Innovative learning tools, including AI book assistants, code context explainers, and text-to-speech.
Product feature icon Thousands of reference materials covering every tech concept you need to stay up to date.
Subscribe now
View plans & pricing
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

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 a Packt Subscription?

Free for first 7 days. $19.99 p/m after that. Cancel any time!
Product feature icon Unlimited ad-free access to the largest independent learning library in tech. Access this title and thousands more!
Product feature icon 50+ new titles added per month, including many first-to-market concepts and exclusive early access to books as they are being written.
Product feature icon Innovative learning tools, including AI book assistants, code context explainers, and text-to-speech.
Product feature icon Thousands of reference materials covering every tech concept you need to stay up to date.
Subscribe now
View plans & pricing

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
$19.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
$199.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 Mex$85 each
Feature tick icon Exclusive print discounts
$279.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 Mex$85 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total Mex$ 3,652.97
Scala Functional Programming Patterns
Mex$1128.99
Scala Design Patterns
Mex$1251.99
Scala for Data Science
Mex$1271.99
Total Mex$ 3,652.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 included in a Packt subscription? Chevron down icon Chevron up icon

A subscription provides you with full access to view all Packt and licnesed content online, this includes exclusive access to Early Access titles. Depending on the tier chosen you can also earn credits and discounts to use for owning content

How can I cancel my subscription? Chevron down icon Chevron up icon

To cancel your subscription with us simply go to the account page - found in the top right of the page or at https://subscription.packtpub.com/my-account/subscription - From here you will see the ‘cancel subscription’ button in the grey box with your subscription information in.

What are credits? Chevron down icon Chevron up icon

Credits can be earned from reading 40 section of any title within the payment cycle - a month starting from the day of subscription payment. You also earn a Credit every month if you subscribe to our annual or 18 month plans. Credits can be used to buy books DRM free, the same way that you would pay for a book. Your credits can be found in the subscription homepage - subscription.packtpub.com - clicking on ‘the my’ library dropdown and selecting ‘credits’.

What happens if an Early Access Course is cancelled? Chevron down icon Chevron up icon

Projects are rarely cancelled, but sometimes it's unavoidable. If an Early Access course is cancelled or excessively delayed, you can exchange your purchase for another course. For further details, please contact us here.

Where can I send feedback about an Early Access title? Chevron down icon Chevron up icon

If you have any feedback about the product you're reading, or Early Access in general, then please fill out a contact form here and we'll make sure the feedback gets to the right team. 

Can I download the code files for Early Access titles? Chevron down icon Chevron up icon

We try to ensure that all books in Early Access have code available to use, download, and fork on GitHub. This helps us be more agile in the development of the book, and helps keep the often changing code base of new versions and new technologies as up to date as possible. Unfortunately, however, there will be rare cases when it is not possible for us to have downloadable code samples available until publication.

When we publish the book, the code files will also be available to download from the Packt website.

How accurate is the publication date? Chevron down icon Chevron up icon

The publication date is as accurate as we can be at any point in the project. Unfortunately, delays can happen. Often those delays are out of our control, such as changes to the technology code base or delays in the tech release. We do our best to give you an accurate estimate of the publication date at any given time, and as more chapters are delivered, the more accurate the delivery date will become.

How will I know when new chapters are ready? Chevron down icon Chevron up icon

We'll let you know every time there has been an update to a course that you've bought in Early Access. You'll get an email to let you know there has been a new chapter, or a change to a previous chapter. The new chapters are automatically added to your account, so you can also check back there any time you're ready and download or read them online.

I am a Packt subscriber, do I get Early Access? Chevron down icon Chevron up icon

Yes, all Early Access content is fully available through your subscription. You will need to have a paid for or active trial subscription in order to access all titles.

How is Early Access delivered? Chevron down icon Chevron up icon

Early Access is currently only available as a PDF or through our online reader. As we make changes or add new chapters, the files in your Packt account will be updated so you can download them again or view them online immediately.

How do I buy Early Access content? Chevron down icon Chevron up icon

Early Access is a way of us getting our content to you quicker, but the method of buying the Early Access course is still the same. Just find the course you want to buy, go through the check-out steps, and you’ll get a confirmation email from us with information and a link to the relevant Early Access courses.

What is Early Access? Chevron down icon Chevron up icon

Keeping up to date with the latest technology is difficult; new versions, new frameworks, new techniques. This feature gives you a head-start to our content, as it's being created. With Early Access you'll receive each chapter as it's written, and get regular updates throughout the product's development, as well as the final course as soon as it's ready.We created Early Access as a means of giving you the information you need, as soon as it's available. As we go through the process of developing a course, 99% of it can be ready but we can't publish until that last 1% falls in to place. Early Access helps to unlock the potential of our content early, to help you start your learning when you need it most. You not only get access to every chapter as it's delivered, edited, and updated, but you'll also get the finalized, DRM-free product to download in any format you want when it's published. As a member of Packt, you'll also be eligible for our exclusive offers, including a free course every day, and discounts on new and popular titles.