© Anto Aravinth, Srikanth Machiraju 2018
Anto Aravinth and Srikanth MachirajuBeginning Functional JavaScripthttps://doi.org/10.1007/978-1-4842-4087-8_1

1. Functional Programming in Simple Terms

Anto Aravinth1  and Srikanth Machiraju2
(1)
Chennai, Tamil Nadu, India
(2)
Hyderabad, Andhra Pradesh, India
 

The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that.

—Robert C. Martin

Welcome to the functional programming world, a world that has only functions, living happily without any outside world dependencies, without states, and without mutations—forever. Functional programming is a buzzword these days. You might have heard about this term within your team or in a local group meeting. If you’re already aware of what that means, great. For those who don’t know the term, don’t worry. This chapter is designed to introduce you to functional terms in simple English.

We are going to begin this chapter by asking a simple question: What is a function in mathematics? Later, we are going to create a function in JavaScript with a simple example using our function definition. The chapter ends by explaining the benefits that functional programming provides to developers.

What Is Functional Programming? Why Does It Matter?

Before we begin to explore what functional programming means, we have to answer another question: What is a function in mathematics? A function in mathematics can be written like this:

f (X) = Y

The statement can be read as “A function f, which takes X as its argument, and returns the output Y.X and Y can be any number, for instance. That’s a very simple definition. There are key takeaways in the definition, though:
  • A function must always take an argument.

  • A function must always return a value.

  • A function should act only on its receiving arguments (i.e., X), not the outside world.

  • For a given X, there will be only one Y.

You might be wondering why we presented the definition of function in mathematics rather than in JavaScript. Did you? That’s a great question. The answer is pretty simple: Functional programming techniques are heavily based on mathematical functions and their ideas. Hold your breath, though; we are not going to teach you functional programming in mathematics, but rather use JavaScript. Throughout the book, however, we will be seeing the ideas of mathematical functions and how they are used to help understand functional programming.

With that definition in place, we are going to see the examples of functions in JavaScript. Imagine we have to write a function that does tax calculations. How are you going to do this in JavaScript? We can implement such a function as shown in Listing 1-1.
var percentValue = 5;
var calculateTax = (value) => { return value/100 * (100 + percentValue) }
Listing 1-1

Calculate Tax Function

The calculateTax function does exactly what we want to do. You can call this function with the value, which will return the calculated tax value in the console. It looks neat, doesn’t it? Let’s pause for a moment and analyze this function with respect to our mathematical definition. One of the key points of our mathematical function term is that the function logic shouldn’t depend on the outside world. In our calculateTax function, we have made the function depend on the global variable percentValue. Thus this function we have created can’t be called as a real function in a mathematical sense. Let’s fix that.

The fix is very straightforward: We have to just move the percentValue as our function argument, as shown in Listing 1-2.
var calculateTax = (value, percentValue) => { return value/100 * (100 + percentValue) }
Listing 1-2

Rewritten calculateTax Function

Now our calculateTax function can be called as a real function. What have we gained, though? We have just eliminated global variable access inside our calculateTax function. Removing global variable access inside a function makes it easy for testing. (We will talk about the functional programming benefits later in this chapter.)

Now we have shown the relationship between the math function and our JavaScript function. With this simple exercise, we can define functional programming in simple technical terms. Functional programming is a paradigm in which we will be creating functions that are going to work out their logic by depending only on their input. This ensures that a function, when called multiple times, is going to return the same result. The function also won’t change any data in the outside world, leading to a cachable and testable code base.

FUNCTIONS VS. METHODS IN JAVASCRIPT

We have talked about the word function a lot in this text. Before we move on, we want to make sure you understand the difference between functions and methods in JavaScript.

Simply put, a function is a piece of code that can be called by its name. It can be used to pass arguments that it can operate on and return values optionally.

A method is a piece of code that must be called by its name that is associated with an object.

Listing 1-3 and Listing 1-4 provide quick examples of a function and a method.
var simple = (a) => {return a} // A simple function
simple(5) //called by its name
Listing 1-3

A Simple Function

var obj = {simple : (a) => {return a} }
obj.simple(5) //called by its name along with its associated object
Listing 1-4

A Simple Method

There are two more important characteristics of functional programming that are missing in the definition. We discuss them in detail in the upcoming sections before we dive into the benefits of functional programming.

Referential Transparency

With our definition of function, we have made a statement that all the functions are going to return the same value for the same input. This property of a function is called a referential transparency . A simple example is shown in Listing 1-5.
var identity = (i) => { return i }
Listing 1-5

Referential Transparency Example

In Listing 1-5, we have defined a simple function called identity. This function is going to return whatever you’re passing as its input; that is, if you’re passing 5, it’s going to return the value 5 (i.e., the function just acts as a mirror or identity). Note that our function operates only on the incoming argument i, and there is no global reference inside our function (remember in Listing 1-2, we removed percentValue from global access and made it an incoming argument). This function satisfies the conditions of a referential transparency. Now imagine this function is used between other function calls like this:
sum(4,5) + identity(1)
With our referential transparency definition, we can convert that statement into this:
sum(4,5) + 1

Now this process is called a substitution model as you can directly substitute the result of the function as is (mainly because the function doesn’t depend on other global variables for its logic) with its value. This leads to parallel code and caching. Imagine that with this model, you can easily run the given function with multiple threads without even the need to synchronize. Why? The reason for synchronizing comes from the fact that threads shouldn’t act on global data when running parallel. Functions that obey referential transparency are going to depend only on inputs from their argument; hence threads are free to run without any locking mechanism.

Because the function is going to return the same value for the given input, we can, in fact cache it. For example, imagine there is a function called factorial, which calculates the factorial of the given number. Factorial takes the input as its argument for which the factorial needs to be calculated. We know the factorial of 5 is going to be 120. What if the user calls the factorial of 5 a second time? If the factorial function obeys referential transparency, we know that the result is going to be 120 as before (and it only depends on the input argument). With this characteristic in mind, we can cache the values of our factorial function. Thus if factorial is called for a second time with the input as 5, we can return the cached value instead of calculating it once again.

Here you can see how a simple idea helps in parallel code and cachable code. We will be writing a function in our library for caching the function results later in the chapter.

REFERENTIAL TRANSPARENCY IS A PHILOSOPHY

Referential transparency is a term that came from analytic philosophy ( https://en.wikipedia.org/wiki/Analytical_philosophy ). This branch of philosophy deals with natural language semantics and its meanings. Here the word referential or referent means the thing to which the expression refers. A context in a sentence is referentially transparent if replacing a term in that context with another term that refers to the same entity doesn’t alter the meaning.

That’s exactly how we have been defining referential transparency here. We have replaced the value of the function without affecting the context.

Imperative, Declarative, Abstraction

Functional programming is also about being declarative and writing abstracted code. We need to understand these two terms before we proceed further. We all know and have worked on an imperative paradigm. We’ll take a problem and see how to solve it in an imperative and declarative fashion.

Suppose you have a list or array and want to iterate through the array and print it to the console. The code might look like Listing 1-6.
var array = [1,2,3]
for(i=0;i<array.length;i++)
    console.log(array[i]) //prints 1, 2, 3
Listing 1-6

Iterating over the Array Imperative Approach

It works fine. In this approach to solve our problem, though, we are telling exactly “how” we need to do it. For example, we have written an implicit for loop with an index calculation of the array length and printing the items. We will stop here. What was the task here? Print the array elements, right? It looks like we are telling the compiler what to do, however. In this case, we are telling the compiler, “Get array length, loop our array, get each element of the array using the index, and so on.” We call it an imperative solution. Imperative programming is all about telling the compiler how to do things.

We will now switch to the other side of the coin, declarative programming. In declarative programming, we are going to tell what the compiler needs to do rather than how. The “how” parts are abstracted into common functions (these functions are called higher order functions, which we cover in the upcoming chapters). Now we can use the built-in forEach function to iterate the array and print it, as shown in Listing 1-7.
var array = [1,2,3]
array.forEach((element) => console.log(element)) //prints 1, 2, 3
Listing 1-7

Iterating over the Array Declarative Approach

Listing 1-7 does print exactly the same output as Listing 1-5. Here, though, we have removed the “how” parts like “Get array length, loop our array, get each element of an array using an index, and so on.” We have used an abstracted function, which takes care of the “how” part, leaving us, the developers, to worry about our problem at hand (the “what” part). We will be creating these built-in functions throughout the book.

Functional programming is about creating functions in an abstracted way that can be reused by other parts of the code. Now we have a solid understanding of what functional programming is; with this in mind, we can explore the benefits of functional programming.

Functional Programming Benefits

We have seen the definition of functional programming and a very simple example of a function in JavaScript. We now have to answer a simple question: What are the benefits of functional programming? This section helps you see the huge benefits that functional programming offers us. Most of the benefits of functional programming come from writing pure functions. So before we see the benefits of functional programming, we need to know what a pure function is.

Pure Functions

With our definition in place, we can define what is meant by pure functions. Pure functions are the functions that return the same output for the given input. Take the example in Listing 1-8.
var double = (value) => value * 2;
Listing 1-8

A Simple Pure Function

This function double is a pure function because given an input, it is always going to return the same output. You can try it yourself. Calling the double function with input 5 always gives the result as 10. Pure functions obey referential transparency. Thus we can replace double(5) with 10, without any hesitations.

So what’s the big deal about pure functions? They provide many benefits, which we discuss next.

Pure Functions Lead to Testable Code

Functions that are not pure have side effects. Take our previous tax calculation example from Listing 1-1:
var percentValue = 5;
var calculateTax = (value) => { return value/100 * (100 + percentValue) } //depends on external environment percentValue variable

The function calculateTax is not a pure function, mainly because for calculating its logic it depends on the external environment. The function works, but it is very difficult to test. Let’s see the reason for this.

Imagine we are planning to run a test for our calculateTax function three times for three different tax calculations. We set up the environment like this:
calculateTax(5) === 5.25
calculateTax(6) === 6.3
calculateTax(7) === 7.3500000000000005
The entire test passed. However, because our original calculateTax function depends on the external environment variable percentValue, things can go wrong. Imagine the external environment is changing the percentValue variable while you are running the same test cases:
calculateTax(5) === 5.25
// percentValue is changed by other function to 2
calculateTax(6) === 6.3  //will the test pass?
// percentValue is changed by other function to 0
calculateTax(7) === 7.3500000000000005 //will the test pass or throw exception?
As you can see here, the function is very hard to test. We can easily fix the issue, though, by removing the external environment dependency from our function, leading the code to this:
var calculateTax = (value, percentValue) => { return value/100 * (100 + percentValue) }
Now you can test this function without any pain. Before we close this section, we need to mention an important property about pure functions: Pure functions also shouldn’t mutate any external environment variables. In other words, the pure function shouldn’t depend on any external variables (as shown in the example) and also change any external variables. We’ll now take a quick look what we mean by changing any external variables. For example, consider the code in Listing 1-9.
var global = "globalValue"
var badFunction = (value) => { global = "changed"; return value * 2 }
Listing 1-9

badFunction Example

When the badFunction function is called it changes the global variable global to the value changed. Is it something to worry about? Yes. Imagine another function that depends on the global variable for its business logic. Thus, calling badFunction affects other functions’ behavior. Functions of this nature (i.e., functions that have side effects) make the code base hard to test. Apart from testing, these side effects will make the system behavior very hard to predict in the case of debugging.

So we have seen with a simple example how a pure function can help us in easily testing the code. Now we’ll look at other benefits we get out of pure functions: reasonable code.

Reasonable Code

As developers we should be good at reasoning about the code or a function. By creating and using pure functions we can achieve that very simply. To make this point clearer, we are going to use a simple example of function double (from Listing 1-8):
var double = (value) => value * 2

Looking at this function name, we can easily reason that this function doubles the given number and nothing else. In fact, using our referential transparency concept, we can easily go ahead and replace the double function call with the corresponding result. Developers spend most of their time reading others’ code. Having a function with side effects in your code base makes it hard for other developers in your team to read. Code bases with pure functions are easy to read, understand, and test. Remember that a function (regardless of whether it is a pure function) must always have a meaningful name. For example, you can’t name the function double as dd given what it does.

SMALL MIND GAME

We are just replacing the function with a value, as if we know the result without seeing its implementation. That’s a great improvement in your thinking process about functions. We are substituting the function value as if that’s the result it will return.

To give your mind a quick exercise, see this reasoning ability with our in-built Math.max function.

Given the function call:
Math.max(3,4,5,6)

What will be the result?

Did you see the implementation of max to give the result? No, right? Why? The answer to that question is Math.max is a pure function. Now have a cup of coffee; you have done a great job!

Parallel Code

Pure functions allow us to run the code in parallel. As a pure function is not going to change any of its environments, this means we do not need to worry about synchronizing at all. Of course JavaScript doesn’t have real threads to run the functions in parallel, but what if your project uses WebWorkers for running multiple things in parallel? Or a server-side code in a node environment that runs the function in parallel?

For example, imagine we have the code given in Listing 1-10.
let global = "something"
let function1 = (input) => {
        // works on input
        //changes global
        global = "somethingElse"
}
let function2 = () => {
        if(global === "something")
        {
                //business logic
        }
}
Listing 1-10

Impure Functions

What if we need to run both function1 and function2 in parallel? Imagine thread one (T-1) picks function1 to run and thread two (T-2) picks function2 to run. Now both threads are ready to run and here comes the problem. What if T-1 runs before T-2? Because both function1 and function2 depend on the global variable global, running these functions in parallel causes undesirable effects. Now change these functions into a pure function as explained in Listing 1-11.
let function1 = (input,global) => {
        // works on input
        //changes global
        global = "somethingElse"
}
let function2 = (global) => {
        if(global === "something")
        {
                //business logic
        }
}
Listing 1-11

Pure Functions

Here we have moved the global variable as arguments for both the functions, making them pure. Now we can run both functions in parallel without any issues. Because the functions don’t depend on an external environment (global variable), we aren’t worried about thread execution order as with Listing 1-10.

This section shows us how pure functions help our code to run in parallel without any problems.

Cachable

Because the pure function is going to always return the same output for the given input, we can cache the function outputs. To make this more concrete, we provide a simple example. Imagine we have a function that does time-consuming calculations. We name this function longRunningFunction:
var longRunningFunction = (ip) => { //do long running tasks and return }
If the longRunningFunction function is a pure function, then we know that for the given input, it is going to return the same output. With that point in mind, why do we need to call the function again with its input multiple times? Can’t we just replace the function call with the function’s previous result? (Again note here how we are using the referential transparency concept, thus replacing the function with the previous result value and leaving the context unchanged.) Imagine we have a bookkeeping object that keeps all the function call results of longRunningFunction like this:
var longRunningFnBookKeeper = { 2 : 3, 4 : 5 . . .  }
The longRunningFnBookKeeper is a simple JavaScript object, which is going to hold all the input (as keys) and outputs (as values) in it as a result of invoking longRunningFunction functions. Now with our pure function definition in place, we can check if the key is present in longRunningFnBookKeeper before invoking our original function, as shown in Listing 1-12.
var longRunningFnBookKeeper = { 2 : 3, 4 : 5 }
//check if the key present in longRunningFnBookKeeper
//if get back the result else update the bookkeeping object
longRunningFnBookKeeper.hasOwnProperty(ip) ?
      longRunningFnBookKeeper[ip] :
      longRunningFnBookKeeper[ip] = longRunningFunction(ip)
Listing 1-12

Caching Achieved via Pure Functions

The code in Listing 1-12 is relatively straightforward. Before calling our real function, we are checking if the result of that function with the corresponding ip is in the bookkeeping object. If yes, we are returning it, or else we are calling our original function and updating the result in our bookkeeping object as well. Did you see how easily we have made the function calls cachable by using less code? That’s the power of pure functions.

We will be writing a functional lib, which does the caching, or technical memorization, of our pure function calls later in the book.

Pipelines and Composable

With pure functions, we are going to do only one thing in that function. We have seen already how the pure function is going to act as a self-understanding of what that function does by seeing its name. Pure functions should be designed in such a way that they should do only one thing. Doing only one thing and doing it perfectly is a UNIX philosophy; we will be following the same while implementing our pure functions. There are many commands in UNIX and LINUX platforms that we are using for day-to-day tasks. For example, we use cat to print the contents of the file, grep to search the files, wc to count the lines, and so on. These commands do solve one problem at a time, but we can compose or pipeline to do the complex tasks. Imagine we want to find a specific name in a text file and count its occurrences. How will we be doing that in our command prompt? The command looks like this:
cat jsBook | grep –i "composing" | wc

This command does solve our problem via composing many functions. Composing is not only unique to UNIX/LINUX command lines; it is the heart of the functional programming paradigm. We call this functional composition in our world. Imagine these same command lines have been implemented in JavaScript functions. We can use them with the same principles to solve our problem.

Now think about another problem in a different way. You want to count the number of lines in text. How will you solve it? Ahaa! You got the answer. The commands are in fact a pure function with respect to our definition. It takes an argument and returns the output to the caller without affecting any of the external environments .

That’s a lot of benefits we are getting by following a simple definition. Before we close this chapter, we want to show the relationship between a pure function and a mathematical function. We tackle that next.

A Pure Function Is a Mathematical Function

Earlier we saw this code snippet in Listing 1-12:
var longRunningFunction = (ip) => { //do long running tasks and return }
var longRunningFnBookKeeper = { 2 : 3, 4 : 5 }
//check if the key present in longRunningFnBookKeeper
//if get back the result else update the bookkeeping object
longRunningFnBookKeeper.hasOwnProperty(ip) ?
      longRunningFnBookKeeper[ip] :
      longRunningFnBookKeeper[ip] = longRunningFunction(ip)
The primary aim was to cache the function calls. We did so using the bookkeeping object. Imagine we have called the longRunningFunction many times so that our longRunningFnBookKeeper grows into the object, which looks like this:
longRunningFnBookKeeper = {
   1 : 32,
   2 : 4,
   3 : 5,
   5 : 6,
   8 : 9,
   9 : 10,
   10 : 23,
   11 : 44
}

Now imagine that longRunningFunction input ranges only from 1 to 11 integers, for example. Because we have already built the bookkeeping object for this particular range, we can refer only the longRunningFnBookKeeper to say the output longRunningFunction for the given input.

Let’s analyze this bookkeeping object. This object gives us the clear picture that our function longRunningFunction takes an input and maps over the output for the given range (in this case it’s 1–11). The important point to note here is that the inputs (in this case, the keys) have, mandatorily, a corresponding output (in this case, the result) in the object. In addition, there is no input in the key section that maps to two outputs.

With this analysis we can revisit the mathematical function definition, this time providing a more concrete definition from Wikipedia ( https://en.wikipedia.org/wiki/Function_(mathematics) :

In mathematics, a function is a relation between a set of inputs and a set of permissible outputs with the property that each input is related to exactly one output. The input to a function is called the argument and the output is called the value. The set of all permitted inputs to a given function is called the domain of the function, while the set of permissible outputs is called the codomain.

This definition is exactly the same as our pure functions. Have a look at our longRunningFnBookKeeper object. Can you find the domain and codomain of our function? With this very simple example you can easily see how the mathematical function idea is borrowed in the functional paradigm world (as stated in the beginning of the chapter).

What We Are Going to Build

We have talked a lot about functions and functional programming in this chapter. With this fundamental knowledge we are going to build the functional library called ES8-Functional. This library will be built chapter by chapter throughout the text. By building the functional library you will be exploring how JavaScript functions can be used (in a functional way) and also how functional programming can be applied in day-to-day activities (using our created function to solve the problem in our code base).

Is JavaScript a Functional Programming Language?

Before we close this chapter, we have to take a step back and answer a fundamental question: Is JavaScript a functional programming language? The answer is yes and no. We said in the beginning of the chapter that functional programming is all about functions, which have to take at least an argument and return a value. To be frank, though, we can create a function in JavaScript that can take no argument and in fact return nothing. For example, the following code is a valid code in the JavaScript engine:
var useless = () => {}

This code will execute without any error in the JavaScript world. The reason is that JavaScript is not a pure functional language (like Haskell) but rather a multiparadigm language. However, the language is very much suitable for the functional programming paradigm as discussed in this chapter. The techniques and the benefits that we have discussed up to now can be applied in pure JavaScript. This is the reason for this book’s title.

JavaScript is a language that has support for functions as arguments, passing functions to other functions, and so on, mainly because JavaScript treats functions as its first-class citizens (we talk more about this in upcoming chapters). Because of the constraints according to the definition of the term function, we as developers need to take them into account while creating them in the JavaScript world. By doing so, we will gain many advantages from the functional paradigm as discussed in this chapter.

Summary

In this chapter we have seen what functions are in math and in the programming world. We started with a simple definition of function in mathematics and reviewed small, solid examples of functions and the functional programming paradigm in JavaScript. We also defined what pure functions are and discussed, in detail, their benefits. At the end of the chapter we also showed the relationship between pure functions and mathematical functions. We also discussed how JavaScript could be treated as a functional programming language. A lot of progress has been made in this chapter.

In the next chapter, we will be reading about creating and executing functions in the ES8 context. Now with ES8 we have several ways to create functions; that’s exactly what we will be reading about in the next chapter.