Book Image

Scala Functional Programming Patterns

By : Atul S. Khot
Book Image

Scala Functional Programming Patterns

By: Atul S. Khot

Overview of this book

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.
Table of Contents (19 chapters)
Scala Functional Programming Patterns
Credits
About the Author
Aknowledgement
About the Reviewers
www.PacktPub.com
Preface
Index

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.