Photo by Behnam Norouzi on Unsplash

Functional Style Versus Functional Programming

Reducing Complexity and Increasing Efficiency

Venkat Subramaniam
6 min readSep 5, 2022

--

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

Some languages and libraries provide a functional style of coding whereas some provide functional programming capabilities. What’s the difference, you may wonder.

Functional style reduces accidental complexity that is prevalent in the imperative style of programming. Functional programming makes the execution of code fairly efficient in addition to reducing complexity. In this article, we’ll discuss these ideas with some examples.

We’ll use a series of examples to illustrate the complexity in imperative style code, how functional style code reduces that complexity, and how functional programming further makes the code efficient.

You’ve seen those fancy displays with stock ticker symbols and prices scrolling through in financial trading buildings and sites. Given a timeslice, suppose you want to know the price for a particular ticker that scrolls by. Let’s assume that the tickers and prices for a timeslice are available as a list, like so:

"AMZN:132", "AAPL:167", "GOOG:115", "INTC:33", "MSFT:277", "ORCL:76"

In the imperative style, we write code to tell what to do and also to convey how to do it. Written in the imperative style, here’s a JavaScript code to find the price for “GOOG” from a list of tickers and prices for a timeslice:

const tickersAndPrice = ["AMZN:132", "AAPL:167", "GOOG:115", 
"INTC:33", "MSFT:277", "ORCL:76"];
let priceForGOOG = 'Not found';for(const tickerAndPrice of tickersAndPrice) {
const [ticker, price] = tickerAndPrice.split(':');
if(ticker === 'GOOG') {
priceForGOOG = `$${price}`;
break;
}
}
console.log(`Price for GOOG: ${priceForGOOG}`);

The output from this code is:

Price for GOOG: $115

The same style, written in Java looks like this:

import java.util.List;public class Imperative {
public static void main(String[] args) {
var tickersAndPrice = List.of("AMZN:132", "AAPL:167",
"GOOG:115", "INTC:33", "MSFT:277", "ORCL:76");
var priceForGOOG = "Not found"; for(var tickerAndPrice: tickersAndPrice) {
var ticketPriceSplit = tickerAndPrice.split(":");
if(ticketPriceSplit[0].equals("GOOG")) {
priceForGOOG = "$" + ticketPriceSplit[1];
}
}
System.out.println("Price for GOOG: " + priceForGOOG);
}
}

In the code written in both the languages, we iterate over the data, look for ticker symbol equal to “GOOG”, and once we find it, assign it to the priceForGood variable, and break out of the loop. In short, we are in the business of controlling the loop flow, properly initializing the variable, and assigning to it. That feels like how we would interact with a toddler — fun to start with, but it gets tiring rather quickly.

In addition to solving the problem, we deal with the how — the details for each step — and that’s the accidental complexity in the imperative style of programming.

In functional style, we use function composition. Instructions or functions are composed into a pipeline and data flows from one function to the next in the pipeline. We focus on what we want to do with the data and leave details like how to iterate to an underlying library of functions.

Here’s the functional style equivalent code, in JavaScript, for the previous imperative style code:

const tickersAndPrice = ["AMZN:132", "AAPL:167", "GOOG:115", 
"INTC:33", "MSFT:277", "ORCL:76"];
const priceForGOOG =
tickersAndPrice.map(data => data.split(':'))
.filter(([ticker, price]) => ticker === "GOOG")
.map(([ticker, price]) => `$${price}`)[0] || 'Not Found';
console.log(`Price for GOOG: ${priceForGOOG}`);

Likewise, here’s the functional style equivalent code, in Java:

import java.util.List;public class Functional {
public static void main(String[] args) {
var tickersAndPrice = List.of("AMZN:132", "AAPL:167",
"GOOG:115", "INTC:33", "MSFT:277", "ORCL:76");
var priceForGOOG = tickersAndPrice.stream()
.map(data -> data.split(":"))
.filter(tickerAndPrice -> tickerAndPrice[0].equals("GOOG"))
.map(tickerAndPrice -> "$" + tickerAndPrice[1])
.findFirst()
.orElse("Not found");
System.out.println("Price for GOOG: " + priceForGOOG);
}
}

In the code written in both the languages, we use function composition and build a pipeline of functions: map to split each piece of data, filter to pass through the data only for “GOOG,” and a map again to pick only the price. We’re not interested in the iteration, but only in conveying what to do for each element as it flows through the pipeline of functions.

In the JavaScript version we used the index operator, [0], to get the first element, whereas in the Java version we used findFirst(). In both the versions if “GOOG” was not found in the data we substituted “Not found” for the price.

Both the versions have reduced complexity when compared to their own imperative style versions. The code reads like the problem statement, we can walk through the functional style versions in a single pass to understand.

However, while the JavaScript version is functional style, the Java version is more like functional programming — it is relatively more efficient. The difference is not in the syntax but in the semantics.

The JavaScript version performs eager evaluation whereas the Java version does lazy evaluation. Eager evaluation is where an expression is evaluated when it’s encountered, irrespective of whether the result is used further along or not. Lazy evaluation, on the other hand, defers evaluation until the result of that expression is actually used. In functional programming, laziness leads to efficiency by avoiding unnecessary computations.

Let’s dig in.

Let’s make a small change to the JavaScript code to take a peek at the data being processed by the pipeline of functions:

function print(data) {
console.log(data);
return data;
}
const priceForGOOG =
tickersAndPrice.map(data => data.split(':'))
.map(data => print(data))
.filter(([ticker, price]) => ticker === "GOOG")
.map(([ticker, price]) => `$${price}`)[0] || 'Not Found';

After this change to the functional version of the JavaScript code, if we run it, we’ll see this output:

[ 'AMZN', '132' ][ 'AAPL', '167' ][ 'GOOG', '115' ][ 'INTC', '33' ][ 'MSFT', '277' ][ 'ORCL', '76' ]Price for GOOG: $115

Each and every value in the timeslice is processed before the price for the desired ticker is picked. Whereas there are libraries in JavaScript that can do better, that’s the behavior of filter() and map() provided in JavaScript. Processing every value will not be efficient if we have to process a large collection of data. The evaluation of the data in the list is rather eager.

Now, let’s tweak the functional code in Java to examine the values being processed.

var priceForGOOG = tickersAndPrice.stream()
.peek(data -> System.out.println(data))
.map(data -> data.split(":"))
.filter(tickerAndPrice -> tickerAndPrice[0].equals("GOOG"))
.map(tickerAndPrice -> "$" + tickerAndPrice[1])
.findFirst()
.orElse("Not found");

After this change to the functional version of the Java code, if we run it, we’ll see this output:

AMZN:132AAPL:167GOOG:115Price for GOOG: $115

The values in the timeslice after “GOOG” were not touched. The reason is that the functional pipeline evaluation is lazy instead of being eager. The functions like filter() and map() are intermediate operations and they’re not triggered until a call to a terminal function like findFirst() is evaluated. Internally, the intermediate operations are fused together. Rather than running each function in the pipeline for all the data, the functional pipeline evaluates a collection of functions, but minimally based on the demands of the terminal operation.

What sets apart functional style from functional programming is efficiency. Both reduce complexity of code, but the latter also considers efficiency.

Functional programming == Functional composition + Lazy evaluation

Some languages like Kotlin and Scala provide the capability for both eager and lazy evaluation. As programmers, we get to choose which one makes sense based on the context of the problem.

We quickly look at the syntax, but we have to see the semantics to notice the difference.

Using functional style in languages that support it can help reduce your code’s complexity. Functional programming adds the benefit of greater efficiency. Think about your programs. Are there any that you could refactor using functional style? How could you take advantage of the efficiency gains from functional programming?

Want to learn more about functional programming? Pick up the beta version of Venkat’s latest book, Functional Programming in Java, Second Edition. Save 35% off the ebook using promo code vsjava2e_medium_35% on https://pragprog.com. Promo codes are not valid on prior purchases.

Cover for Functional Programming in Java, Second Edition Venkat Subramaniam featuring three paint brushes dragging squiggles of green, red, and yellow paint.
Cover of Functional Programming in Java, Second Edition

--

--