The functional programming (FP) paradigm pushes this reasoning further by considering computational design as being based on mathematical functions and the immutability of state and data. FP's guiding principle is that the entire computer program should be a single, referentially transparent expression. At its core, the concept of FP requires that functions be pure, referentially transparent and free of side effects. A function is pure when, given the same input, it always returns the same output. It is referentially transparent when its functional expression is interchangeable with its corresponding value anywhere inside a computer program. It is free of side effects when it does not modify an application's state outside of its scope. Thus, for example, modifying a variable that is declared outside of its scope or echoing a message to a screen are considered to be functional side effects that must be avoided as much as possible.
An example of a pure function would be as follows:
function myJS()
{
function add(n1, n2)
{
let number1 = Number(n1);
let number2 = Number(n2);
return number1 + number2;
}
}
The next function is not pure, because there are two side effects:
function myJS()
{
function add(n1, n2)
{
// 1. Modifies the global scope
number1 = Number(n1);
number2 = Number(n2);
// 2. The alert function
alert( number1 + number2 );
}
}
A referentially transparent function can be replaced, anywhere inside the code, with a constant that equals the functional expression's computed value:
4 === addTwo(2);
For example, this function is not referentially transparent:
function myJS()
{
function addRandom(n1)
{
let number1 = Number(n1);
return number1 + Math.random();
}
}
Amongst the most notable JavaScript functions that are not referentially transparent and that generate side effects, we can mention these: Date, Math.random, delete, Object.assign, Array.splice, Array.sort, and RegExp.exec.
There are many advantages of keeping functions simple and pure. The most important ones are:
- Simpler critical paths, whereby the developer's cognitive burden is reduced when trying to maintain or update an application
- Easier testing of functions
- Free compiler optimizations, whereby a compiler might decide to replace a functional expression with its corresponding constant value at compile time, rather than computing the function each time
- Future performance boosts due to runtime optimizations
- Safe multithreading by avoiding race conditions due to application state mutability (JavaScript is single threaded for now, but who knows what the future holds)