DEV Community

Acid Coder
Acid Coder

Posted on • Updated on

Function: The Savior of Scope. The Story Of Immutability And Declarative.

You likely heard of the term Functional Programming, that it is declarative, immutable, pure function(no side effect) and it uses recursion over loop.

Immutable, declarative, pure function and recursion, we repeat these words every time we talk about functional programming

But why?

Today we are going to examine how immutability, declarative, pure function and recursion are related to each other and why we cant mention one without mentioning the rest.

Immutability

First let us review why we want to avoid mutable variables if possible by comparing it to immutable variables

Possible mistake with mutable variables:

let temperature = 30
let distance = 3000
//...others code
temperature = 2000 // mistake, you should change the distance!
// ...others code
displayTemperature(temperature) // mistake 1
displayTemperature(distance) // mistake 2
Enter fullscreen mode Exit fullscreen mode

Possible mistake with immutable variables:

const temperature = 30
const distance = 3000
//...others code
temperature = 2000 // compiler will complain!!
// ...others code
displayTemperature(temperature) // no problem
displayTemperature(distance) // mistake 1
Enter fullscreen mode Exit fullscreen mode

both mutable and immutable suffer from the same mistake: reading them at wrong places

This is not something compiler can take care of, you need to write tests to mitigate mistakes like this.

However, mutable variables has one extra point of failure: assigning value to a wrong variable. It can be very hard to debug because value assignment can happen in anywhere.

We can mitigate wrong variable value assignment by writing tests too, but writing tests take away our precious engineering time. Mistake like this can be prevented by using immutable variables.

Prevention is better than cure.

Declarative Code

We heard of "imperative" and "declarative" a lot, but how to tell which code is imperative and which code is declarative?

The keyword of writing a declarative code is "expression".

If we can express a piece of code as a value, then it is an expression, example:

can be expressed as a value:

condition ? 1 : 2
Enter fullscreen mode Exit fullscreen mode

cannot be expressed as a value:

if(condition){
    1
} else {
    2
}
Enter fullscreen mode Exit fullscreen mode

Simple enough, but how is this related to immutability?

Meaningful Value

A value has to have a purpose, else it would be pointless to create the value in the first place

so what is the purpose of a value?

Recall what computer do: accept an input, process it, and output the result

A value is only meaningful if we read it(turn the output into another input)

Turn an expression into an input:

By assigning it to a variable, preferably immutable variable:

const input = condition ? 1 : 2

doSomething(input) 
Enter fullscreen mode Exit fullscreen mode

By reading the expression directly:

doSomething(condition ? 1 : 2)
Enter fullscreen mode Exit fullscreen mode

Turn non-expression code into an input:

By mutable variable:

let input = null

if(condition){
    input = 1
} else {
    input = 2
}

doSomething(input)
Enter fullscreen mode Exit fullscreen mode

This is bad, because we need to rely on mutable variable to escape if scope

By var or global variable:

if(condition){
    var input = 1
} else {
    input = 2
}

doSomething(input)
Enter fullscreen mode Exit fullscreen mode
if(condition){
    input = 1
} else {
    input = 2
}

doSomething(input)
Enter fullscreen mode Exit fullscreen mode

I believe I don't need to explains why they are terrible ideas.

By running the side effect in the if scope:

if(condition){
    doSomething(1)
} else {
    doSomething(2)
}
Enter fullscreen mode Exit fullscreen mode

doSomething is a side effect, it has to be one. Because in the end it either end up sending the data somewhere else or storing the data in a database or display the data on a screen(become an input of our brain).

If not, then doSomething is meaningless, our if statement is meaningless.

We coupled doSomething into the if statement. Which mean it is not possible to test the if statement without testing the side effect doSomething.

Scope {}

Notice that scopes {} from statements like if, try catch, switch, for, while... are the reason why we need mutable variable to access values generated in scopes.

Scope limit the access to variables, this a good mechanism but we need to sacrifice immutability.

The more we nest our scope, the more we rely on mutable variables.

Which mean scope nesting not only affect our code readability, it also affects our code correctness.

Bad readability produces bugs, bad readability and mutable variables produce even more bugs!

So should we give up on scope?

No, in fact we can create immutable variable from scopes.

Function, The Savior of Scope

Not only function scope can limit the accessibility of variables, it allow us to read a value from scopes without creating any mutable variable.

From the same example:

const getResult = (condition) => {
  if(condition){
      return 1
  } else {
      return 2
  }
}

const input = getResult(false)

doSomething(input)
Enter fullscreen mode Exit fullscreen mode

checking the list:
✅ scope
✅ immutable
✅ pure function

However this does not work with loop scope, loop always end up with mutable variable or side effect.

const getSumUpToN= (n) => {
  let sum = 0 // mutation
  for(let i = 1; i <= n ;i ++){ // mutation
     sum += i
  }
  return sum   
}

const input = getSumUpToN(5)

doSomething(input)
Enter fullscreen mode Exit fullscreen mode

Recursion

This is where recursion enter the picture. We can use recursion to preserve the immutability.

Function is the key to make recursion possible.

const getSumUpToN= (n) => {
   return n <= 0 ? 0 : n +  getSumUpToN(n - 1)
}

const input = getSumUpToN(5)

doSomething(input)
Enter fullscreen mode Exit fullscreen mode

Now we understand why functional programming use recursion over loop, it is because recursion can express loop as an value and avoid mutable variables

We also understand why functional programming is functional, it is because function is an expression and it make recursion possible.

Summary

  1. The foundation of functional programming is expression(value)
  2. The tool is function. Function can turn everything into expressions by returning values from scopes and use recursion over loop.
  3. The result is a flattened code where it is unnecessary to limit the accessibility of variables
  4. The main benefits are immutability and pure function(improve code correctness), the extra benefit is declarative(improve readability).

Final Thoughts

I believe the point of functional programming is to remove the need of scope.

We need scope to limit accessibilities of variables in order to code safer, but at the same time scope either introduce mutable variable or couple side effects into statements.

By using function, we can maintain immutability and decouple from side effect while limiting accessibilities of variables.

I hope this article give you a clear idea of how to write a basic functional code and why you need to write one.

Stay vigilant fellow programmers!

Top comments (0)