In this fourth installment of his series on the Scala programming language, Venkat delves into the functional style of programming in Scala.
Hello again! In this fourth installment of our series on the Scala language, we discuss the functional style of programming in Scala.
In the last article we saw the pure OO side of Scala. Scala also supports functional style; however, it does not enforce the style, so it’s often called a fully OO, hybrid functional language.
When designing Scala, Martin Odersky took a bold, unconventional step of bringing two different paradigms together, the OO and functional. This is not a trivial undertaking as these two styles are quite dissimilar and this marriage of distinct paradigms poses some real challenges.
Let’s first take a look at what it means to be functional. There are two defining aspects to the functional style of programming—the purity of functions and programming with higher-order functions.
Purity means that functions have no side-effects. The output of a function is predictably the same as long as the input is the same. A pure function is not affected by and does not affect anything outside; it also does not mutate any value.
There are two benefits of function purity. It’s easier to understand and prove the correctness of such a function. Furthermore, pure functions promote referential transparency; in plain English, pure functions can be easily rearranged and reordered for execution on multiple threads, making it easier to program concurrency on multicore processors.
Scala does not enforce purity, though it makes it easy to detect where mutable variables are used—simply search for vars. It is a good practice for us to use vals and immutability as much as possible when programming in Scala.
The other aspect of function style is working with higher-order functions—this is the facility that treats functions as first-class citizens. We can pass functions to functions, create functions within functions, and return functions from functions. This allows for functional composition and so in Scala we can design using both functional composition and object composition, as we desire or as appropriate.
Let’s explore these with some examples. We’ll start with some small examples that manipulate numbers so we can easily learn how to use higher-order functions (we’ll learn how to create functions that accept other functions in a future article). We will conclude with a practical example where we’ll apply the concepts we’ve learned.
Let’s start with a simple iteration: given a list of stock prices, we’d like to print each price on a separate line.
At first thought, the traditional for loop comes to mind, something like this in Java:
or is it < instead of <= in the loop condition?
There is no reason to burden ourselves with that. At the least we should use the for-each construct in Java, like so,
Let’s follow this style in Scala.
Scala’s type inference determines the type of the prices list to be List[Double] and the type of price to be Double. The above style of iteration is often referred to as an external iterator. Scala also supports internal iteration, so we could write the above example using the foreach function of List.
The foreach function is a higher order function: it receives as parameter another function.
In general a function has four parts: name, parameter list, return type, and body. Of these four, the body is the most important. In the previous function that’s passed to foreach, the body is between the => and the closing }. The parameter list has one parameter e and since Scala can infer type, we did not have to say e : Double, though we could. Scala already knows the return type of this function based on what foreach expects and this function is anonymous, so does not have any name. The anonymous function we passed above is called a function value in Scala.
Scala has the smarts to allow us to reduce the code even further. If we simply pass the parameter received in the function value to another function in the body, like in this example, we can let Scala do that job.
That reduced some noise in the code; the parameter was received in the function value and passed to println.
We can take this up another notch: in an earlier article in this series we discussed how Scala makes quite a few things optional, including dot. So, we can refactor the above code to
Here we’re sending the println function itself as a parameter to the foreach method instead of wrapping a call to it into a function value—the println function itself is treated here as a function value.
All right, we know how to use the functional style to iterate over elements: simply pass a function value that operates on an element to the internal iterator and it takes care of calling that function value with each element in the list as a parameter.
There are different flavors of internal iterators available on collections in Scala. Let’s look at the benefits a few of these offer.
If we want to pick the first price that’s greater than $500, we can do that without mutating any variables.
If we want all the prices that are greater than $500, then replace find with the filter function.
If we have to compute ten percent of each of the prices given, once again we can achieve this elegantly using the map function.
The map function applies the function value given, once for each element in the list, collects the result from the function value (which is 10% of the price in this example) into a list, and finally returns the collected list.
Finally, say we’re asked to total the prices given. We’re quite familiar with how to do that in the imperative style.
to get the output of
However, a variable was tortured in the making of this example. We can avoid that with functional style again.
The reduce function takes a function value that accepts two values. In the first call to the function value, e1 is bound to the first element in the list and e2 is bound to the second element. In each of the subsequent calls to the function value, e1 is bound to the result of the previous call to this function value and e2 to the subsequent elements in the list. The reduce function returns the result from the last call to the function value once it has been applied for each of the elements in the list.
We’ve seen a few functions here: foreach, find, filter, map, and reduce. It’s time to put these to a practical use.
Functional programming emphasizes immutability, but it’s equally about designing with state transformation and function composition.
In OO programming we strive for good object composition. In functional programming we design with function composition. Rather than mutating state, it is transformed as it flows through the sequence of functions.
Let’s prepare an example to see the difference between imperative style and functional style. We’re given a list of ticker symbols and our goal in this example is to find the highest priced stock not exceeding $500.
Let’s start with a sample list of ticker symbols.
For convenience (and to avoid cryptic symbols in code) let’s create a case class to represent a stock and its price (case classes are useful to create immutable instances in Scala that provide quite a few benefits including ease in pattern matching).
Given a ticker symbol we want to get the latest stock price for that symbol. Thankfully, Yahoo makes this easy.
We fetch the latest stock price from the Yahoo URL, parse the result, and return an instance of StockPrice with the ticker symbol and the price value.
To help us pick the highest-priced stock valued not over $500, we need two functions, one to compare two stock prices and the other to determine if a given stock price is not over $500.
Given two StockPrice instances, the pickHighPriced function returns the higher priced. The isNotOver500 will return a true if the price is less than or equal to $500, false otherwise.
Here’s how we would approach the problem in imperative style:
Let’s walk through the code to see what we did.
First we create an instance of ArrayBuffer, which is a mutable collection. We invoke the getPrice() function for each ticker and populate the stockPrices ArrayBuffer with the StockPrice instances.
Second, we iterate over these stock prices and drop from this mutable collection those stocks that are valued over $500. This results in possibly fewer elements than we started with.
Finally we loop through the collection one more time to pick the stock that is valued the highest among them, again mutating the highestPricedStock variable as we navigate the collection using the external iterator.
We can improve on this code further, use multiple collections if we desire, wrap the code into separate functions, and put them into a class if we like. However, that will not affect the fundamental approach we took: imperative style with mutable data structure. The state of the collection of stocks and their prices went through quite a few mutations.
Let’s write this code in functional style. Ready?
That’s it, it’s small enough to fit into a tweet. OK, this conciseness takes some getting used to.
tickers map getPrice first transforms the collection of tickers into a collection of StockPrice instances. For each ticker symbol, now we have the name and price in this collection. The filter function then applies the isNotOver500 on that collection and transforms that into a smaller collection of StockPrices with only stocks whose price does not exceed $500. The reduce function takes that further to pick the highest-priced stock, which we finally hand over to the print method of StockPrice.
In addition to being concise, the code does not mutate any state. The state goes through transformations as it flows through the composed functions.
While this code is elegant and concise, what about debugging and performance? These are two questions I’m often asked.
From the debugging point of view, there are no mutable states, so there are fewer options for errors than in code with several mutable parts. We can write unit tests on each of the intermediate steps separately and also on the collective results. We can step through the code individually or collectively. You can also store the intermediate values in immutable vals along the way so we could examine those.
If the collection is fairly small we won’t see any significant performance impact. If the collection is fairly large, we may face some copy overhead. Let’s not reject the goodness of functional style in the name of performance. Prototype and see if performance is a concern for what you have to implement. If the performance is adequate, then you have gained from what the paradigm has to offer. If performance is not reasonable then you can explore options to improve it. One option is to use persistent data structures—these are immutable data structures that perform intelligent selective copying to provide close to constant-time copy performance.
I hope this article whets your appetite for learning further and using the functional style of programming in Scala. In the next article we’ll see how Scala collections make use of this style to provide a concise and fluent interface.
Dr. Venkat Subramaniam is an award-winning author, founder of Agile Developer, Inc., and an adjunct faculty at the University of Houston.
He has trained and mentored thousands of software developers in the US, Canada, Europe, and Asia, and is a regularly-invited speaker at several international conferences. Venkat helps his clients effectively apply and succeed with agile practices on their software projects.
Venkat is the author of .NET Gotchas, the coauthor of 2007 Jolt Productivity Award winning Practices of an Agile Developer, the author of Programming Groovy: Dynamic Productivity for the Java Developer and Programming Scala: Tackle Multi-Core Complexity on the Java Virtual Machine. His latest book is Programming Concurrency on the JVM: Mastering Synchronization, STM, and Actors.