Programming: Using pure functions to design better programs

Well designed functions can dramatically simplify the mind numbing process of designing programs by neatly encapsulating bits of program logic. Badly designed functions, however, can be a huge cause of bugs (and hair loss).

Functional programming, in contrast to object oriented programming, is a programming paradigm that uses the beauty of well designed pure functions to write concise programs. Understanding some functional programming concepts can help you design better functions — and ultimately better programs — even in opinionated object oriented languages.

What is a function?

Functions in programming are borrowed from mathematics, and it is useful to understand the original mathematical definition of functions.

. . . 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. — Wikipedia

From the definition above, it is clear that a true function should always return the same output given a specific set of inputs.

Pure functions

Consider the following function:

// javascript
var a = 10
function add_to_a(x){
a += x
return a
}

The function add_to_a above violates the core principle outlined above. We can easily see that by calling the function twice as follows:

add_to_a(10)
// returns 20
add_to_a(10)
// returns 30

The function returns different values given the same input. This is an impure function.

A pure function will always return the same output given some input.

A function can also be considered an impure function if it has side effects. A side effect is an action that changes some state or variable that was not explicitly passed to the function. For example, the add_to_a function above changes the variable a, which was not explicitly passed to it as a function parameter.

The following function is an improvement of the add_to_a above which satisfies the first principle, but is still an impure function because it has a side effect:

// javascript
var a = 10
function add_to_a(x){
a += x
return 0
}

Though the function above will always return the same output (0) for a given input value, it mutates ‘a’ which was not explicitly passed to it.

A pure function will only mutate its input parameters, and will cause no other visible side effects

Just these two functional concepts can help you design better functions that simplify your code. Here is an example of how you would purify the add_to_a above:

// javascript
function add(a, x){
a += x
return a
}
var a = 10;
add(a, 10); // would correctly add 10 to a

Notice that the abstracted add function above can be used to perform any similar addition task elsewhere in our code, and not just the one in question.

Pure functions in real life

Here is a more concrete real life example of how you can use pure functions to abstract an operation and simplify your code. Here is some code taken from an actual JavaScript codebase:

// javascript
function total_item_cost(){
var total = 0
    for(var i = 0; var i < items_in_cart.length - 1; i++){
total += items_in_cart[i]["price"];
}
    return total
}

The function above loops through items_in_cart and returns the total cost. It is looks nice and simple, but is laden with impurity. This function depends on the items_in_cart variable, and will return a different value depending on its state. We have no clue where that variable is defined or declared within the parent scope.

Here is an approach at a better design of this function:

// javascript
function calculate_total(list, parameter){
var total = 0
    for(var i = 0; var i < list.length - 1; i++){
total += list[i][parameter];
}
    return total
}

This is a pure, and far more useful function than the previous one. It calculates the total of “parameter” for each of the items in the list. It can now be used not only for items_in_cart but for other things within the application that require the same logic:


var total_cost = calculate_total(items_in_cart, "price")
// can be used for other things too
var total_marks = calculate_total(students, "marks")
var total_read_time = calculate_total(users, "read_time")

Summary

Using pure functions can help you really find the core of some program logic and abstract that into reusable and most importantly, easily testable bits of code.


We’re hiring!

Does this stuff interest you? Do you want to work on an effective, tightly knit agile team? We’re hiring!