Functional Programming with JavaScript

Functional Programming with JavaScript

For all the folks out there starting their programming journey as well as those who have been programming for quite a some time, you all might have come across the term functional programming at some point or you definitely will.

In this blog I'll try my best to explain you what exactly functional programming is and how we can use functional programming in our java-script codes.

What is Functional Programming ?

In layman's terms functional programming is nothing but a coding style. Many of the popular languages support functional programming coding style. Some of them are : Haskell, Scala, Elm, Clojure, JavaScript etc..

However, in this blog we'll be talking about functional programming styles supported by java-script. The reason for that being we all love java-script. And also because I don't have much experience with other languages.

Defining in a more eloquent way, we say Functional Programming is a programming paradigm. Paradigm.. gosh its a heavy word, so paradigm is basically the worldview or a way of looking at things, be it the components or the elements you are using in your program ( our world as programmers ).

Now before moving ahead with functional programming, I want to take a detour to other paradigms available out there we've been using and might not be aware of that.

  1. Imperative
  2. Object Oriented
  3. Declarative
  4. Functional

In the Imperative paradigm the program follows the instructions/commands as specified and in their sequential order.

With object oriented we handle the changing state of variables by packaging them in small units called objects which are instances of classes with all the functionalities.

Then comes the Declarative paradigm wherein we only care about the final output of the program and not the overall implementation. SQL (Structured Query Language) is the perfect example of declarative paradigm.

For functional paradigm, there is just one simple idea: use pure functions. That's it.

Pure Functions ??

Pure Functions are the functions which depend only on their input and nothing else i.e they'll have some input values and based on those input values they'll always return an output. They do not depend on anything from the outside world. Also, pure functions do not have any side effects.

Let's see an example :

// impure function

let message = 'world';

function greet(){
       console.log( 'Hello ' + message );
}

greet();   // Hello world

message = 'JavaScript';
greet();   // Hello JavaScript

In the above example we have a function named greet(), which consoles a sentence on the screen. Now as we discussed earlier, a pure function depends only on its input values and not on the outside world. But here the function is accessing the global variable message. Thus violating the first condition of pure functions. Also instead of returning the output, our function here produces a side effect (console the output), clearly a red lag here as well. And lastly, even though we called the function exactly the same way each time still it produces a different output. Hence, greet is not a pure function.

//pure function

function wish(message){
    return 'Hello '+message;
}

wish('World');   // Hello World
wish('JavaScript');     // Hello JavaScript

Now this time, wish() functions satisfies all the criteria's of a pure function. It depends only on its input, returns an output without producing any side effect, and for a given input always return the same output. Hence, wish is a pure function.

Why Functional Programming is better ?

Now that you have got a gist of what functional programming is, what are pure functions, and how to write one. The next question that might pop up in your head is why should I be switching to functional programming ? I mean its easier to console.log whatever I want. Plus I've been doing it for years. So why switch now !!

Well, following are some of the reasons that might encourage you to start using functional programming as a daily practice:

1. More Predictable and Safer

As we saw earlier pure functions only depend on their input values and not on the outside world, so they become more predictable. We know what should be output based on our input values and thus it becomes difficult to introduce any bugs in the code or anything of that sort.

2. Easier to Test/Debug

Now since we know what output should our function be returning, we can easily test it for all input values and debug in case of any issues. Debugging becomes easy because we don't have to worry on what values our function might be working upon. We already know about the input values and what output should they be producing, debugging in case of errors becomes quite easy.

3. Easier than Object-oriented JavaScript

When working with object-oriented java-script, things often tend to get a bit tricky. We are using prototypes, this operator and other methods and they often don't work as we expect them to be, or we run into an unexpected situation. These things seem to be normal with object-oriented java-script. But with functional programming this all goes away. Everything we write in our code is a pure function. We know how exactly they'll behave. So no more unexpected errors with functional java-script.

Let's Get Started

Moving ahead with some programs I want to tell you about some guidelines which we should be following while doing functional programming.

Everything is a function

When doing functional programming you have to move ahead with this basic idea that whatever I write in my program should be a pure function. Say I want to do multiple things, so each of those needs to be implemented via pure functions which communicate with each other.

Below is an imperative program which does not use functional programming

let movieName = 'The Dark Knight';
let director = 'Christopher Nolan';

console.log(movieName + ' was directed by ' + director);
// The Dark Knight was directed by Christopher Nolan 

movieName='Inception'
console.log(movieName + ' was directed by ' + director);
// Inception was directed by Christopher Nolan

This approach is working but its not very functional. So with a pure function this would look something like

const getMovieAndDirector = (movie, director)=> {
      return movie+' was directed by '+ director;
  }

getMovieAndDirector('The Dark Knight', 'Christopher Nolan'); 
// The Dark Knight was directed by Christopher Nolan 

getMovieAndDirector('Inception', 'Christopher Nolan');
// Inception was directed by Christopher Nolan

Avoid Side Effects

So as we are all aware till now that in functional programming we should only be writing pure functions. So to do that one thing which we can always keep in mind is to avoid any kind of side-effects or whatsoever. By avoiding side-effects I want that your function should not be doing anything else other than returning the output after all the necessary computations. So we need to avoid our habit of using console.log everywhere.

Below is a function with some side effects:

// function with side-effect
const printMessage = (superhero) => {
   console.log(' I like '+ superhero);
}

printMessage('Iron Man'); 
// I like Iron Man

Though the function printMessage depends only on its input value still it is not a pure function because of the side effect present inside the function. We can solve this problem as below

// pure function
const printMessage = (superhero) => {
   return ' I like '+ superhero;
}

printMessage('Iron Man'); 
// I like Iron Man

Now the printMessage function is a pure function because this time it is returning the output string.

Avoid Mutability

Another important thing to take care of while writing a pure function is to avoid mutability of data. Whenever making some updation on data or variables instead of changing them our approach should be to generate new data. The reason for this being let's say we are working on some feature of an application with some important data involved. There could be a high chance that another of our team member is working on some other feature using the same data. Now updating the data in such a case would not be an ideal choice. Instead we should take that data to generate new data set as per our requirements. This also helps in preserving the original state of the data.

Lets see an example to better understand it:

// change in place
let avengers = [{name :'Tony Stark', superheroName : 'Iron Man'},
{name: 'Steve Rogers', superheroName: 'Captain America'}]

const addNewAvenger=(avengers, newAvenger) =>{
  avengers[avengers.length] = newAvenger;
  return avengers;
}

addNewAvenger(avengers, {name: 'Bruce Banner', superheroName: 'Hulk'})
// returns an array of 3 objects
/*
[{name :'Tony Stark', superheroName : 'Iron Man'},
{name: 'Steve Rogers', superheroName: 'Captain America'},
{name: 'Bruce Banner', superheroName: 'Hulk'}]
*/

console.log(avengers)

When we execute the above piece of code, the function addNewAvenger returns an array of objects as expected. However, if you try to console.log the initial avengers array you'll find that the array has changed. Go on.... try executing the above piece of code in your browser and you'll see how our initial array changed. This is something we must try to avoid while writing pure functions.

So instead of changing the array in the function we must return a new array.

Lets see how that is done.

let avengers = [{name :'Tony Stark', superheroName : 'Iron Man'},
{name: 'Steve Rogers', superheroName: 'Captain America'}]

const addNewAvenger=(avengers, newAvenger) => [...avengers, newAvenger]

addNewAvenger(avengers, {name: 'Bruce Banner', superheroName: 'Hulk'})

console.log(avengers)

Now on executing the above function you'll find that it does not change our original array and returns a new array with the new object inserted. Go on... try this as well.. For those wondering about the three dots before the avengers array, its nothing but spread operator. You can read more about it here: spread operator in JS. Did you notice the difference between these two pieces of code.

Use Higher-Order Functions

Functions in java-script are often referred to as first class citizens. They can be passed as arguments to other functions, returned from functions, assigned to variables and can be added to arrays as well.

The functions which accept other functions as arguments or return functions are called Higher Order Functions. Another advantage of functional programming is that the functional programming toolset provides us various higher order functions which we can use for a variety of tasks such as array.map(), array.filter(), array.reduce()

array.map : The map() method creates a new array populated with the results of calling a provided function on every element in the calling array

map calls a provided callback function once for each element in an array, in order, and constructs a new array from the results. callback is invoked only for indexes of the array which have assigned values (including undefined).

Below example explains the map function

let array = [2,4,6,8];

// returns an array with square of each number
const getSquare = (arr) => arr.map(number => number*number)

getSquare(array) 
// [4,16,36,64]

You can read more about map: array.map()

array.filter : The filter() method creates a new array with all elements that pass the test implemented by the provided function.

filter() calls a provided callback function once for each element in an array, and constructs a new array of all the values for which callback returns a value that coerces to true.

Below example explains the filter function

let array = [1,2,3,4,5,6];

// return an array of even numbers 
const getEvenNumber = (arr) => arr.filter(number => number%2===0)

getEvenNumber(array) //[2,4,6]

You can read more about filter: array.filter()

array.reduce :The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in single output value.

reduce function takes a callback function with accumulator and currentvalue as arguments of the callback function and an initial value passed onto the reduce function along with the callback.

Below example explains the reduce function

let array = [1,2,3,4];

// returns the sum of array elements
const getSum = (arr) => arr.reduce((accumulator, currentValue) => 
accumulator + currentValue ), 0 )

getSum(array) // 10

You can read more about reduce: array.reduce

Data Flow Through Functions

When writing a program in the functional style think of your program as data flowing through a set of successive functions. What happens in this is that output of one function becomes the input to another function. Currying and Function Composition can be used to denote this behavior of functions.

Function Currying : Currying is a transformation of functions that translates a function from callable as f(a, b, c) into callable as f(a)(b)(c).

Lets look at an example for the same:

function addLater(currentValue){
  return function(secondValue){
        return currentValue + secondValue;
  }
}

addLater(2)(5); // 7

The above implementation show data flow through function currying using closures. Read more about closure

Function Composition: Function composition is an approach where the result of one function is passed on to the next function, which is passed to another until the final function is executed for the final result. Function compositions can be composed of any number of functions.

Lets look at an example for the same:

const double = x => x*2;
const square = x => x*x;

const compose = (...fun) => x => fun.reduce((y, f)=>f(y), x)

let result = compose(square, double)(3)
// 18

Read more about function composition

Conclusion

I hope after reading this article you have got a clear understanding of what exactly is functional programming, what are pure functions, how to write pure functions, why functional programming is more preferred and what are the guidelines to be followed while writing functional programs.

You can also refer to some other sources to get more understanding about functional programming:

Master the JavaScript Interview: What is Functional Programming click here

An Introductions to functional Programming in JavaScript click here

Anjana Vakil - Functional Programming in JS: What? Why? How?