A matter of purity
Tags: functional, pure, functions
Published: 2020-07-09 19:06:22

---
title: A matter of purity
published: true
description: What are **pure** functions? And why should you even care? 
tags: #fp #pure #functions
---

![Graal](https://dev-to-uploads.s3.amazonaws.com/i/mngjdcgjazxkmd69x8rc.jpg)

Hello folks, 
for my second post I've chosen a more philosophical topic: **pure functions**. 

I ended my first article talking about the concept of functions in FP, saying that:

> functions in FP are just mapping between inputs and outputs (and nothing more)

This is an informal definition of **_pure functions_**.

Other definitions you may have heard are:

* pure functions are functions in the mathematical sense
* pure functions are functions that will return the same output anytime they are given the same input 
* pure functions are functions without side effects

The mathematical definition of a function is the following: 

> Given two non-empty sets **X** and **Y**, a function **_f_** from **X** to **Y** is a relation such that **for all** _x_ in _X_ there exists only one _y_ in _Y_ such that _(x, y)_ belongs to _f_, or, said otherwise, such that **_y = f (x)_**

(note the **for all** is crucial because what we are looking for are **total** functions)

So, why should you care about pure functions? 

Well, the reason is that the use of pure functions will help you write correct programs. 

How? (you  might be wondering)

Let's see. 

## Local reasoning 

You may have heard about **local reasoning** or not. What it refers to is the ability to reason about what a piece of code does **in isolation**, meaning you don't need any knowledge about the context in which said piece of code is executed to understand what it does. 

How pure functions relate to local reasoning? Well, if a function takes care only of transforming an input value in an output one, without relying on any other external piece of information, that function enables of course **local reasoning** about what it is doing. 

Let's look at an example of a function that does not allow **local reasoning**

```kotlin
var counter = 1; 

fun `not easy to reason about`(anInt: Int) =
	if (counter < 5) {
		counter = counter + 1
		anInt * 2
	} else {
		counter = counter + 1
		anInt * 3
	}
}
```

Why is that? Of course, because the logic of the function relies on the **_mutable_**, **_global_** _counter_ variable. 

The same example can be translated into a more familiar setting for those of you who are more accustomed to `Java` and `OOP` (instead of `Kotlin`)

```java
public class TheOne {
	
	private int counter = 0;
	
	public notEasyToReasonAbout(int anInt) {
		int result; 	
		if (counter < 5) {
			result = anInt * 2;
		} else {
			result = anInt * 3;
		}
		counter = counter + 1;
		
		return result;
	}
	
}
```

I guess you have seen many classes like `TheOne` shown here. 

What is the problem? Again the fact the method `notEasyToReasonAbout` is relying on the value of the **mutable** _counter_ that is out of its scope (this time is not _global_ but still has a lifespan that goes beyond that of the method execution and it can mutate over it). 

>## DISCLAIMER
>Am I saying that the OOP way of doing things is intrinsically **impure**? Not at all. 
>It is just that languages like Java tend to make it easier to use constructs that work against **local reasoning** (like mutability) while others (think of modern languages like Kotlin, or Scala) choose to make it easier to use constructs that make it easier to apply **local reasoning** (examples are the `val` keyword that introduces immutable references, the default choice of immutable collections over mutable ones and so on).

## Referential transparency

Once you start adopting pure functions in your codebase you gain another capability you were missing before, **referential transparency**. What is it about? 

Say you have a piece of code like 

```kotlin
val x = aFunction(y)
```

If `aFunction` is a pure function you gain the ability to safely replace any occurrence of `aFunction(y)`, provided that y is immutable, with x, because x will **always** be the result of applying `aFunction` to `y`. 

Have you ever heard of temporal coupling? Well if you use **pure functions** you can forget about it and move around your values as you please. 

### Question time

Do you think the following function is referentially transparent? 

```kotlin
fun `read file lines`(path: String): List<String> = 
	File(path).readLines()
```
#### Answer

No. The reason is that anytime you call this function, even with the same path as input, you are not sure you will get the same results. Reasons may be 

- the file doesn't exist anymore (then you'll get an exception)
- the file has been modified (so the content will differ)
- the file permissions have been changed and you no longer have read permission (once again you'll get an exception)

You may be wondering how can one write pure functions that do things like IO but I won't talk about this topic right now (you will have to wait for a new article :smirk:).


## Function composition

The beauty of pure functions is that you can *compose* them or, going the other way around, you can split a big function into pieces and then compose them together to obtain the initial function.

If you think about it, writing a program to solve a need can be abstracted to writing one big function that turns our program input in its outputs. 

As usual, the approach one takes is: divide et impera! But what's the point of splitting a problem in subproblems if you cannot glue back the solutions to the subproblems into an overall solution? 

With pure functions, function compositions is a matter of having matching types. 
Given `f: B -> C` and `g: A -> B`, they can be composed to obtain `h: A -> C`, because the output type of `g` matches the input type of `f`, so `h = f . g` 

## Conclusion

Once you start using pure functions, you will start to think more and more in terms of types and of functions as mappings between types. 

Your workflows/use cases (whatever you are calling them) will naturally emerge from the types of the functions you have developed to solve the smaller bits of your problem domain.

**Follow the types!**

You will end up doing **TDD**: Types Driven Development!