Saurabh.v

@saurabhgiv

Functional Programming Concepts: Pure Functions

May 14th 2017

Functional programming is getting lot of attention these days due to the advantages it offers like parallelism, easier testing, predictability and many others.

Pure functions is a concept mainly used in functional programming languages but it can be applied in any programming paradigm.

What are pure functions ?

There are two conditions that a function must satisfy to be called pure.
Let’s understand these two conditions one by one.

Given same argument to the function, it should always return same output.

How can we be certain that above mentioned point holds while writing pure functions?

Follow me to get the answer!

Function must not use state of the program to compute its output.
x = 5        # x is a global variable
multiply(y):
return y*x

multiply is not a pure function because its output is computed using global variable x. If the value of x changes, output of multiply function also changes for same input.

x = 5
multiply(2) # returns 10
x = 10         # value of global variable x changed from 5 to 10
multiply(2): 20

In above example input to multiply function is same but output has changed depending on the state of the program.

Global variable x is also known as the state of the program because it can be accessed in any part of the program and defines the data associated with a program during its execution.

Since multiply function is not giving same output for same input, it is not pure.

To make multiply pure, we can pass global variable x as argument to it.

def multiply_pure(y, x):
return y*x
multiply_pure(2, 3)    # returns 6
multiply_pure(2, 3) # returns 6

No matter how many times we call multiply_pure with same input, it will always return same output.

Secondly, a function must not take mutable objects as arguments and should not use it to compute output of the function when working in a concurrent programming environment.

This is because concurrent processes can modify mutable object and ultimately modify the output of a function.
Following example illustrates the above mentioned point:

# returns length of the list passed as argument
def compute_length(elements):
return elements.length()
Mutable elements list being modified by multiple processes

In between the time when argument elements is passed to compute_length and length of elements is returned by compute_length function, it may happen that the length of elements list is modified by another process. This is because elements is a shared mutable list which can be accessed by multiple processes.

Hence compute_length is not pure in concurrent programming environment.

Thirdly, a function must not take any input from the I/O to be pure.
# takes input from the user and turns it into a greeting
def greet():
str = raw_input() # take input from user
str = "Hello " + str
return str

In above written example, output of the function may change depending on the input taken from the I/O.

Evaluation of the result should not cause any side effects such as mutation of mutable objects or output to I/O devices

Pure function should not mutate any mutable object.

Let’s follow below written example to validate statement written above:

class Box:
def __init__(self, length):
self.length = length

# doubles length of Box object
# Assumption: Only box objects are passed
def double_length(box):
box.length = box.length * 2
return

carton = Box(5)          # a Box object is created
double_length(carton) # length of carton is doubled
print carton.length # prints 10

Here double_length function is impure as it modifies mutable Box object.

Doubts ??

Let’s understand it step by step

  • carton(Box object) is passed by reference to double_length function in above example.
  • Any changes to Box object inside the function will be visible outside the function. So we can say that Box object is accessible to whole program, which means that Box object is nothing but state of the program.
  • And a function must not modify state to be called pure.
Pure function should not output to I/O.
# prints text
def printer(text):
print “printing…. ” + text

I/O can be print on a console, write to a database etc.

Conclusion

Any function which interacts with the state of the program is a potential candidate for causing side effects. State of the program can be global variables, mutable objects, I/O operations etc.

And any function which causes side effects is not pure !!

Please hit the ♥ button if you liked the article so that other Medium users might find it and dig it too.

More by Saurabh.v

More Related Stories