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

Preface

This is a book on functional programming patterns using Scala. Functional programming uses functions as basic building blocks. These are functions that don't have any side effects. This challenges our notions about how to write programs. The order of execution for such functions does not matter. We get to reason about them in a referentially transparent manner. This can be a big help in proving correctness. It feels just like a plain arithmetic problem, where (2+2)*(3+3) always equals 24. You may evaluate the expression as 2+2 first, or as 3+3.

I got to know about the Unix culture early in my career. The Unix philosophy relies on pipelining small programs, each doing functionally one and only one thing. One can connect these processing nuggets together. In addition to these hundreds of ready-made building blocks, you could write your own too. These could be easily connected in the pipeline. These pipes and filters were a deeply influential concept as a whole. When I saw Scala's combinators, options, and for comprehensions, I knew I was looking at pipes and filters again. The nuggets in this case were Scala functions instead of Unix processes. Understanding functional programming gives you a new perspective on your code and programming in general. The other aspect of pipelining is that you tend to reuse them intuitively, and you also write less. Though you iterate lines of a text file in a Unix shell pipeline, you don't write any for loops. These are done for you. You just specify which lines pass your criteria or how to transform these lines or both.

Scala allows you to do just that—albeit in a somewhat different form. You don't need to write a for loop, and you keep away from loop counters. Instead, the language invites you to write for comprehensions. Immutability is an actively advocated rule of thumb. Another is avoiding side effects. Scala advocates both. As you probably know, immutability paves the way for more robust concurrency. Why are these so important? Simple, we need to reason about code. Any strategy that makes this activity controlled and simpler is a godsend! Does going down the immutable route mean we end up doing too much copying? How would this Copy On Write measure up against large data structures? Scala has an answer for this in the form of structural sharing.

One-liners are very popular as they get a lot done in a line of code. Scala features allow you to compose such one-liners. Instead of reiterating the same collection, you can do it in one elegant expression. For example, creating an immutable class with constructor and equality comparison defined that is bestowed with destructuring powers is just a one-liner. We just define a case class. There are many situations where Scala one-liners save a lot of programmer time and result in far less code. Combinators such as map, flatMap, filter, and foreach are composed together to express a lot of logic in a one-liner. How does it all affect a program design and design patterns? Here are a few illustrative cases. The singleton design pattern is used to ensure that only one instance of a class could ever exist. Null Objects are specialized singletons that are used to avoid nulls and null checks. Scala's Options give us a similar functionality. Scala's object keyword gives us ready-made singletons. Singletons are specialized factories. A factory creates objects. Scala's syntactic sugar give us a very succinct way to use the apply factory method.

The command design pattern encapsulates an object as a command. It invokes a method on the object. Scala has parameters by name. These are not evaluated at the call site but instead are evaluated at each use within the function. This feature effectively replaces the command pattern with first-class language support. The strategy pattern encapsulates algorithms and allows us to select one at runtime. In Java, we could express the strategy as an interface and the varying algorithms as concrete implementations. Scala's functions are first-class objects. You can pass functions around as method arguments and return values. Functions can be very effective substitutes for the strategy pattern. The ability to define anonymous functions is really helpful here. The Decorator pattern is needed at times. It can be used to decorate (that is, extend) the functionality of an object without modifying it. Some design plumbing needs to be done though. Scala's stackable traits can express the same design very elegantly. One use of the proxy design pattern is for implementing lazy evaluation. When some computation is expensive, we do it only when needed.

As we are very familiar with eager evaluations, we create a list in memory and think it is fully realized. However, just like eager lists, there are lazy lists too. If we think of a typical OR (||) conditional statement, if the left operand is true, the right is not evaluated. This is a very powerful concept. Scala's streams provide lazy lists.

Chain of responsibility is another handy pattern that is used to decouple the sender of a request from its receiver and allows more than one object (a chain of objects) to handle a request. If any object in the chain is not able to handle the request, it passes the request to its next object in the chain. Scala's partial functions fit this bill nicely. We can chain partial functions with Scala's orElse operator to realize the pattern. When we write code, we need to handle errors. Scala's Try/Success/Failure again allows us to write pipelines, and if any piece of the pipeline is an error, rest of the pipeline processing is skipped.

We will look at all these concepts in greater detail. We will set up a problem, look at the traditional Java solution, and then see how Scala changes the game.

Welcome to the Scala wonderland!

What this book covers

Chapter 1, Grokking the Functional Way, gives you an eagle's eye view of functional programming and its advantages: succinct and readable code. Also, this chapter compares the command pattern in Java and Scala.

Chapter 2, Singletons, Factories, and Builders, covers singletons and Null Objects as specialized singletons. Scala Options are null objects. This also covers Scala's support for factory method and builders.

Chapter 3, Recursion and Chasing Your Own Tail, discusses the concept of recursion and Scala's support for it. It also looks at how recursion advocates immutability and the concept of structural sharing.

Chapter 4, Lazy Sequences – Being Lazy, Being Good, talks about eager versus lazy evaluation and the proxy design pattern. It also talks about Scala's streams and infinite lists.

Chapter 5, Taming Multiple Inheritance with Traits, covers Scala traits, mix-ins, and stackable modifications. It also covers dependency injection and the Cake pattern.

Chapter 6, Currying Favors with Your Code, covers lexical scope, closures, partially applied functions, and currying. This chapter also discusses the loan pattern, template method pattern, and another way to implement decorators.

Chapter 7, Of Visitors and Chains of Responsibilities, covers the Visitor pattern and its application. The other topics that are discussed are Scala's pattern matching capabilities and the chain of responsibility pattern. We will also learn Scala implementation using orElse and the collect idiom.

Chapter 8, Traversals – Mapping/Filtering/Folding/Reducing, covers iterators and functional iteration using map, filter, fold, and reduce. This chapter introduces Monads and explains ReduceLeft and ReduceRight.

Chapter 9, Higher Order Functions, discusses the strategy pattern and Scala version using higher order functions. It covers map as a functor, flatMap as a Monad, and foldLeft as Monoids. Here, you will also learn how to iterate lazy collections.

Chapter 10, Actors and Message Passing, showcases a case study to recursively grep a directory for files that contain matching text. It also covers the producer consumer pattern and the Master Slave pattern. It explains the concept of poison pills, event-driven programming, immutability, and concurrency. It also talks about Akka and Actors and how to reimplement recursive grep using Actors.

Chapter 11, It's a Paradigm Shift, teaches you how to sort in Scala and the Schwarzian transform implemented in Scala. It discusses functional error handling with Try/Success/Failure. And talks about Java Threads versus Scala's Futures. Scala's Parser Combinators are also discussed here.

What you need for this book

You would need Scala installed—a version greater than or equal to 2.11. I refer to pipelining a lot, so it would be pretty helpful if you are trying out the examples on Linux or Mac. You can use cygwin too if it is a Windows box you are running.

Version 0.13 of the sbt tool (http://www.scala-sbt.org/) will also be needed.

A typical Java dev environment is assumed too. The examples are tested with Maven version 3 and JDK 8.

Who this book is for

We assume that you have written Java code for a while. You also should have a basic knowledge of Scala. A knowledge of Java and Scala fundamentals is assumed. Familiarity with basic data structures such as binary trees and linked lists is assumed.

This is a text about patterns and design ideas that you can use again and again. A basic understanding of design patterns would be great. I have explained the problem and the patterns and the typical object-oriented Java solution. The Scala solution builds on top of all this know-how. The text also assumes that you have written some multithreaded Java code. I have explained the necessary concepts, but haven't explained multithreading from the ground up.

Most of the concepts are explained and pointers are provided for further reading.

Conventions

In this book, you will find a number of text styles that distinguish between different kinds of information. Here are some examples of these styles and an explanation of their meaning.

Code words in text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input, and Twitter handles are shown as follows: "We can include other contexts through the use of the include directive."

A block of code is set as follows:

// Driver code
public static void main(String[] args) {
    Driver c = new Driver();
SomeInterface c1 = c.create(10); // 2
    SomeInterface c2 = c.create(20); // 3
    
 c1.printMsg(); // prints 10
c2.printMsg(); // prints 20
 }

Any command-line input or output is written as follows:

scala> def f(n: Int) = { 
     |   val k = (y: Int) => y < n // 1
     |   k 
     | } 
f: (n: Int)Int => Boolean 

New terms and important words are shown in bold. Words that you see on the screen, for example, in menus or dialog boxes, appear in the text like this: "Clicking the Next button moves you to the next screen."

Note

Warnings or important notes appear in a box like this.

Tip

Tips and tricks appear like this.

Reader feedback

Feedback from our readers is always welcome. Let us know what you think about this book—what you liked or disliked. Reader feedback is important for us as it helps us develop titles that you will really get the most out of.

To send us general feedback, simply e-mail , and mention the book's title in the subject of your message.

If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, see our author guide at www.packtpub.com/authors.

Customer support

Now that you are the proud owner of a Packt book, we have a number of things to help you to get the most from your purchase.

Downloading the example code

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

Errata

Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you find a mistake in one of our books—maybe a mistake in the text or the code—we would be grateful if you could report this to us. By doing so, you can save other readers from frustration and help us improve subsequent versions of this book. If you find any errata, please report them by visiting http://www.packtpub.com/submit-errata, selecting your book, clicking on the Errata Submission Form link, and entering the details of your errata. Once your errata are verified, your submission will be accepted and the errata will be uploaded to our website or added to any list of existing errata under the Errata section of that title.

To view the previously submitted errata, go to https://www.packtpub.com/books/content/support and enter the name of the book in the search field. The required information will appear under the Errata section.

Piracy

Piracy of copyrighted material on the Internet is an ongoing problem across all media. At Packt, we take the protection of our copyright and licenses very seriously. If you come across any illegal copies of our works in any form on the Internet, please provide us with the location address or website name immediately so that we can pursue a remedy.

Please contact us at with a link to the suspected pirated material.

We appreciate your help in protecting our authors and our ability to bring you valuable content.

Questions

If you have a problem with any aspect of this book, you can contact us at , and we will do our best to address the problem.