Benefits of Pure Functions
Pure Functions are used heavily in functional programming. It is easy to understand the definition of a Pure Function. We have already covered it in the earlier topics. It takes enough experience and hands-on practice to realize the benefits of a pure function. However, you might need to understand some critical benefits at the high level even before jumping into learning a functional programming language. Let's look at some of the significant benefits as listed below.
Pure functions encourage safe ways of programming
The side effects are surprising for everyone. Most of the time, we look at the function name and try to guess the functionality. A function with side effect requires you to look at the documentation or the source code. On the other side, Pure Functions are small, precise, simple, safe and straightforward to reuse. A pure function guarantees that they will not modify anything outside their body. You can use them with confidence because you know that they take input and give output. They do not surprise you.
Pure functions are more composable or modular
It is common in FP to combine many functions into a simple solution. You will often see Functional Programming code written as a chain of function calls. The pseudocode shown below represents a chain of function calls.
val x = mydata.doThis(a). .thenThis(b) .andThenThis(c) .doThisToo(d) .andFinallyThis(e)
The above code takes a dataset and applies a chain of functions. You can do similar things with non-pure functions as well, but it is easy for pure functions because they do not have side effect and the output depends only on the input values. We refer this capability as functional composition. You can combine multiple functions more confidently if you know that there are no side effects.
Pure functions are easy to test and refactor
Since there are no side effects and the output depends only on the input, your test cases are straightforward. You just need to pass the known value and assert the expected value. Whereas simulating the side effects is a real challenge for testing. For example, let's assume you have two functions.
- Unpure Hello World
- Pure Hello World
The first Function is not pure so it prints Hello World on the console. The second function is pure, so it returns Hello World and does not write anything on the console. You can quickly automate the test case to assert the return value. However, writing a test code to assert the console output may be a challenge. Similarly, you can refactor the pure functions confidently. As long as you are not changing the input parameters and output value, any change in the function body does not impact the other part of your application.
Pure functions are memoizable
The memoization is nothing but caching of deterministic functions. If you know that your Function is Pure, and you may need the results again, you can cache the output. Your compiler can also do the caching as an optimization. However, if you have side effects, you cannot cache the results for later use.
Pure functions can be lazy
Lazy evaluation is a compelling idea in the Functional
world. The laziness is mostly used to create data structures to handle large
of data efficiently. Apache Spark libraries are the most common examples. If you
Spark RDD, they implement all transformations as lazy operations. The primary idea
the lazy operation is to linger the evaluation of an expression until a later
This behavior is incredibly powerful because it allows the system to combine the
activities and choose an optimal method to achieve the overall result.
I have listed the laziness as a separate topic on our top 10 list. So keep reading, and I will explain this behavior with appropriate examples.
Pure Functions | Referential Transparency | Benefits of pure functions | First class functions | Higher order function | Anonymous functions | Immutability | Tail Recursion | Expressions in Scala | Lazy Evaluations | Pattern Matching | Closures