As a developer, I believe that entering into the Functional Programming (FP) world is like erasing all that you have learned so far and relearn everything, although not from scratch.
This article aims at going through every fine step introducing and explaining the core concepts of functional programming. We will see how we usually write code in imperative programming and then go about implementing it using the functional programming approach.
In essence, this article should serve as an introduction to the functional programming world for a smooth transition from the usual imperative programming world. So, let’s dive right in.
Note that we will be using Swift language for our programs/ examples throughout the blog. However, even if you don’t belong to the iOS development world, you should be able to follow along smoothly.
Table of Contents
What is Functional Programming?
Functional programming heavily emphasizes on the usage of functions that contains a set of code/ instructions to perform a generic set of operations. In simple terms, Functional programming (FP) is a paradigm which concentrates on computing results rather than on performing actions. When you call a function in a program written with a functional approach, the only significant effect that the function has, is usually to compute a value and return it instead of us giving it a finite set of step-by-step instructions to get the desired results.
Although, in the functional programming world, behind-the-scenes, the function is, as usual, using its own set of instructions which eventually uses up the CPU time, allocating and writing onto the memory. However, from the programmer’s point of view, the primary effect is the return value. Basically, it is more like an encapsulation of a usual set of instructions providing you with a higher order APIs which you can use to execute those encapsulated instructions to perform certain operations.
Core concepts in Functional Programming
1. Pure Functions
Any function/ method in a functional programming world is a pure function.
Notice how the ‘add()’ function doesn’t access the value of the variables: ‘a’ & ‘b’. Instead, it simply takes its own input parameters: ‘x’ & ‘y’, does the required operation on top of them and returns it back to the caller. So, any function in the functional programming world is simply a pure function/ method.
2. Immutable Objects
Objects that we deal with in a functional programming language are often immutable (a.k.a. constant or final). So, instead of changing an object’s properties to modify it, you will allocate a new object which just looks like the old one except for the change that’s taking place.
In a nutshell, all the objects in the functional programming world are immutable. This is a key concept when running programs in multi-threaded environments. So, with functional programming implementations, your code is safe.
Note that there are no variables in functional programming per definition, although stored values are still called as variables despite being constants.
Let’s look at the previous example again:
Notice how the inputs to the pure function: x & y aren’t modified. When such programs run in multi-threaded environments, it is much safer when compared to having variables. We will see this in action in the upcoming sections.
3. Declarative Programming
Functional Programming is a subset of declarative languages that has a heavy focus on recursions. Yes, instead of directly using loops, FP uses recursions to perform an operation which can be achieved with immutability. Loops, on the other hand, require mutability.
Functional programming is otherwise called a declarative language. Ok, what’s declarative now? Well, to understand this, let’s compare it with the imperative approach.
Imperative Vs Declarative Programming
|Traditional Approach||Non-Traditional Approach|
|The focus is on what steps the computer should take rather than what the computer should do.||The focus is on what the computer should do rather than how it should do it|
|We give it a “step-by-step recipe” to obtain the results.||It is like saying “this is what I want, now you figure out how to do it”|
Let’s take an example of adding numbers from 1 to 10.
This is how we do it in imperative programming using a loop:
Notice how the value of the variable ‘total’ is modified inside the loop which embraces mutability.
On the other hand, functional programming uses the recursive mode and this is how it can be achieved:
Notice how recursion, the functional approach, accomplishes the same as the for loop by calling itself with a new start (start + 1) and a new accumulator (total + start). It doesn’t modify the old values. Instead, it uses new values calculated from the old.
Consider this program running in a multi-threaded environment where one thread tries to access the variable’s value while another thread mutates it. This might lead the program to an unstable state. The recursive approach or the state of immutability is the safest in such cases. Hence, functional programming is definitely effective than imperative or traditional programming.
Let’s now move on to understanding Higher Order Functions (HOF) which are a seed terminology in the functional programming world. We will also see functional programming concepts in action using Swift HOFs.
Higher Order Functions
A Higher Order Function (HOF) is a function that takes one or more arguments as functions and returns a function as its result.
Let’s take a look at the major HOFs included in Swift’s standard array library –
The map method solves the problem of transforming elements of an array using a function.
Consider building a simple contacts application where we want to list out details of all contacts. We need a list screen for this and in effect, a list of contacts array in the first place.
Let’s start with creating a struct/ data structure to represent the contact object:
We now have the data structure ready. Let’s create an array of contact objects next –
So, we have 3 objects in our ‘contacts’ array. Let’s say we want to derive the full name of the contact i.e. first name followed by the last name. Usually, in imperative programming, this is how we would achieve it:
We simply loop through the objects and derive the full name by extracting the values of ‘firstName’ & ‘lastname’ properties of each object from the ‘contacts’ array and append the value into a new array.
But with swift’s HOF/ map function, we can just pass the function to the method where we define the rules and extract the data in the format we need.
Here, when the map method is called on the ‘contacts’ array, we simply pass a function that returns only the merged string of ‘firstName’ & ‘lastName’ properties. Basically, we pass a function to the map method by calling it on ‘contacts’ array, which contains objects of type ‘Contact’. It returns an array of objects of type ‘String’. Given this HOF is mostly used for the transformation of array objects from one form/ type to another form/ type, it is rightly called a “map”.
The filter method solves the problem of selecting the elements of an array that pass a certain condition.
Continuing with our contacts app, let’s say we want to filter out the contacts whose age is greater than 20.
The imperative approach would be something like this –
We simply loop through the objects in the array and compare every object with the given condition. We then append the object that satisfies the condition to a newly declared array ‘filteredContacts’.
On the other hand, with functional programming, we can achieve the same by simply calling it upon the array object and passing the condition like this –
Note the use of Swift’s HOF equivalent “filter” here. We pass a function to the filter function which has the rule of validating the ‘age’ property to be greater than 20. The filter method finally returns an array with contact objects matching age > 20.
The reduce method solves the problem of combining the elements of an array to a single value.
Let’s assume that all the contacts in our app are readers of this blog. Also, assume Contact has ‘duration’ property which represents how long a reader reads our blog. We now want to understand how many hours our blog has been read by all of our contacts combined.
In imperative programming, we will loop through all the objects and accumulate the sum in a variable (which is prone to mutability) –
To write it in a thread-safe way, we can use the immutability approach in FP and use Swift’s ‘reduce’ HOF like this –
‘reduce’ method takes 2 parameters –
(i) First represents the starting value from which it should start accumulating
(ii) Second represents the operation (e.g. addition in the above example) which should be performed on the values.
In case you are interested, we have an interesting article on higher order functions and higher order components in React.
We covered the core concepts of functional programming by trying out examples. This should have given you a good understanding of how these functional programming concepts can be easily applied to our implementation/ code.
Popular frameworks like React are heavily influenced by functional programming and hence, they have been widely recognized specifically for their functional approach.
Here are the key takeaways –
- Group/ Generalize/ Break the common set of code into independent functions.
- Do not iterate over the arrays. Instead, use ‘map’ & ‘reduce’.
- Use recursions instead of loops.
Now that we have seen the implications of functional programming, it can be heavily leveraged to combine & use along with Reactive programming. This takes us to a whole new world of Functional Reactive Programming (FRP).
Go ahead to explore our blog on FRP which is an amalgamation of Functional & Reactive programming.