Image by Bro Studio via Shutterstock

Scala and Functional Style: A Practical Example by Venkat Subramaniam

An excerpt from Functional Programming: A PragPub Anthology

The Pragmatic Programmers
4 min readApr 11, 2023

--

✒ Editor’s note: The Pragmatic Bookshelf has a wide selection of books on functional programming topics. You can start by reading Functional Programming: A PragPub Anthology directly on Medium, or browse some of our other offerings.

https://pragprog.com/newsletter/
https://pragprog.com/newsletter/

Functional programming emphasizes immutability, but it’s equally about designing with state transformation and function composition.

In object-oriented programming, we strive for good object composition. In functional programming, we design with function composition. Rather than mutating state, state is transformed as it flows through the sequence of functions.

Let’s construct an example to see what this difference between imperative and functional style looks like in practice. Let’s say we’re given a list of ticker symbols and our goal is to find the highest-priced stock not exceeding $500.

Let’s start with a sample list of ticker symbols.

​ val tickers = List("AAPL", "AMD", "CSCO", "GOOG", "HPQ", "INTC",
​ "MSFT", "ORCL", "QCOM", "XRX")

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, especially ease in pattern matching, a common functional style you’ll see explored in depth in Chapter 10, Patterns and Transformations in Elixir).

​ case class StockPrice(ticker : String, price : Double) {
​ def print =
​ println("Top stock is " + ticker + " at price $" + price)
​ }

Given a ticker symbol, we want to get the latest stock price for that symbol. Thankfully, Yahoo makes this easy.

​ def getPrice(ticker : String) = {
​ val url = s"http://download.finance.yahoo.com/d/quotes.csv?s=${ticker}&f=snbaopl1"
​ val data = io.Source.fromURL(url).mkString
​ val price = data.split(",")(4).toDouble
​ StockPrice(ticker, price)
​ }

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.

​ def pickHighPriced(stockPrice1 : StockPrice, stockPrice2 :
​ StockPrice) =
​ if(stockPrice1.price > stockPrice2.price) stockPrice1
​ else stockPrice2

​ def isNotOver500(stockPrice : StockPrice) = stockPrice.price < 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:

​ import scala.collection.mutable.ArrayBuffer

​ val stockPrices = new ArrayBuffer[StockPrice]
​ for(ticker <- tickers) {
​ stockPrices += getPrice(ticker)
​ }

​ val stockPricesLessThan500 = new ArrayBuffer[StockPrice]
​ for(stockPrice <- stockPrices) {
​ if(isNotOver500(stockPrice)) stockPricesLessThan500 += stockPrice
​ }

​ var highestPricedStock = StockPrice("", 0.0)

​ for(stockPrice <- stockPricesLessThan500) {
​ highestPricedStock =
​ pickHighPriced(highestPricedStock, stockPrice)
​ }

​ highestPricedStock print
​ //Top stock is AAPL at price $377.41

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 pick only stocks that are valued less than $500 and add to the stockPricesLessThan500 ArrayBuffer. This results in possibly fewer elements than we started with.

Finally, we loop through the second collection 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.

Now let’s write this code in functional style. Ready?

​ tickers map getPrice filter isNotOver500 reduce pickHighPriced print

We’re done. That’s it, small enough to fit in a tweet. OK, this conciseness does take some getting used to. Let’s walk through it.

tickers map getPrice first transforms the collection of tickers into a collection of StockPrice instances. For each ticker symbol, we now 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 prices do 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.

Granted that this functional code is elegant and concise, but what about other considerations, like ease of debugging and performance? These are two concerns I often see raised.

--

--

The Pragmatic Programmers
The Pragmatic Programmers

We create timely, practical books and learning resources on classic and cutting-edge topics to help you practice your craft and accelerate your career.