
Functional JavaScript: Pure functions
In my previous article, I talked about what functional programming is and a simple example of how to write non-functional code to functional. I did give a brief description of what a pure function is but I will dig deeper in this article
Pure Functions
A pure function is an independent function that returns an output based on the input, does not rely on external mutable state or produce side effects (alter external state, network and database calls) and does not modify the arguments passed to it. For the same input the output will always be the same. They make for simple reusable blocks in your code base.
When asked, “What are the advantages of writing in a language without side effects?,” Simon Peyton Jones, co-creator of Haskell, replied, “You only have to reason about values and not about state. If you give a function the same input, it’ll give you the same output, every time. This has implications for reasoning, for compiling, for parallelism.”
An example of a pure function is Math.cos(9). Running this will always return the same value no matter where, when or how many times you run it. The response will always be `-0.9111302618846769` and if you replace the function with this value you can be confident nothing will break.
Impure functions
Now that it’s clear what pure functions are, here’s a brief description and a few examples of what impure functions are and do.
An impure function can have a side effect (i.e network/database call), can mutate the values passed to it and the return value does not solely depend on the input.
Math.random() always has a different output value with every invocation. This means it is impure and you cannot replace this value `0.2620022373037849` in place of the function.
console.log is also impure since it causes a side effect by logging to the console.
Benefits of Pure Functions
Debugging.
Since a pure function does not depend on any external state, it means you do not have to look at the external scope when debugging. This makes things easier.
Testing.
A pure function is independent thus testing is basically about testing the outputs of particular inputs. No side effects to mock or stub.
Easy to reason about.
It’s easy to tell what a pure function algorithm is doing as it does not perform any I/O or cause any side effects, or depend on an external state.
Parallelization.
From Wikipedia’s functional section:
If there is no data dependency between two pure expressions, then their order can be reversed, or they can be performed in parallel and they cannot interfere with one another.
If the entire language does not allow side-effects, then any evaluation strategy can be used; this gives the compiler freedom to reorder or combine the evaluation of expressions in a program
With this, it becomes easier to write concurrent applications using FP
Referential Transparency.
Referential Transparency is when you can substitute the output of an expression for the expression without experiencing a change in behavior. Substituting an expression with its result value is possible if the result is computed based only on the input and not dependent on any side effects that may cause uncertainties.
From HaskellWiki, they define Referential Transparency as:
Referential transparency is an oft-touted property of (pure) functional languages, which makes it easier to reason about the behavior of programs. I don’t think there is any formal definition, but it usually means that an expression always evaluates to the same result in any context
Pure functions will always return the same output for the same value and this then means you can simply replace the expression with the output value.
This also helps with caching optimizations such as memoization.
Memoization
Since for the same input we get the same exact output, we can cache the computed result and return it every time the function is called, thus preventing the function being executed again if the result value exists. The purpose of this is to increase performance.
Wikipedia defines memoization as:
In computing, memoization is an optimization technique used primarily to speed up computer programs by storing the results of expensive function calls and returning the cached result when the same inputs occur again.