Functional programming concepts based on my understanding on Avengers and JavaScript
I am a big fan of Avengers. In this post I am trying to explain the JavaScript functional programming concepts based on my understanding on Avengers and JavaScript.
Pure Functions
I have lot of sympathy towards Gamora as she is deprived of her parent’s love,emotionally manipulated and finally killed by her adopted father. She had a lifetime of torment and victimhood.
We will try to represent her character at different time intervals in a function.
//lets assume she has three emotions const emotions= ['cool', 'angry', 'sad']function gamora(emotion){ let time= new Date().getFullYear()let gomuraBehavior= `In ${time}, gamora is ${emotion}`return gomuraBehavior}gamora(emotions[0]) //"In 2019, gamora's emotion - cool" gamora(emotions[1]) //"In 2019, gamora's emotion - angry" gamora(emotions[2]) //"In 2019, gamora's emotion - sad"
One of the major setback of this function is that its not pure. With change in time, for the same input it will give different output. To make it pure, we should rewrite it like below by taking time out of the function and receive it as a parameter.
function gamora(time, emotion){const gomuraBehaviour= `In ${time}, gamora's emotion - ${emotion}`return gomuraBehaviour}const diffEmotions= {2019:'cool',2014:'sad',2009:'angry'}const keys = Object.keys(diffEmotions)gamora(keys[0], diffEmotions[keys[0]]) //In 2009,gamora's emotion- angrygamora(keys[1], diffEmotions[keys[1]]) //In 2014,gamora's emotion- sadgamora(keys[2], diffEmotions[keys[2]]) //In 2019,gamora's emotion- cool
A pure function gives same output for a given input always and it will not change the anything outside its scope. Now the above gamora function is time independent.
Immutability
Time travel concept is a blessing in disguise for the Avengers. It helped them to win against Thanos. Thanos did a great mistake by not freezing the world after he destroyed half of the world population. It gave a chance for Avengers to come back and do a time travel where they were finally successful in not only restoring the world to its old state but also won the battle.
//Below is the world object after Thanos destroyed half of its //populationconst world = {population: 'halved', result:'thanos-won'}
Avengers came and changed the world object .
world.population='restored'world.result='avengers-won'
Now the world object is changed and everyone is happy.
Console.log(world)//{population: "restored", result: "avengers-won"}
If Thanos had frozen the world after destruction, using Object.freeze, then avengers never had a chance.
const world = {population: 'halved', result:'thanos-won'}//Thanos freezes the world Object.freeze(world)//Avengers trying to restore world.population= 'restored' //Throws error in strict modeconsole.log(world) //{population: 'halved', result:'thanos-won'}//Avengers failed to restore the world :(
Shared state
Some of the Avengers successfully overpowered Thanos in a scene. Both Spider-man and Iron-man were almost successful in taking Infinity Gauntlet from Thanos’s hand. But Star-Lord foils the attempt as he physically attacks Thanos after coming to know about Gamora’s death which makes Mantis loose her control over Thanos. In their quest to win over Thanos, Avengers failed as their result was affected by the action of one of their peers.
Likewise, in Javascript when we are having a state which is shared between different functions gets updated, there is always a chance that we wont get the desired result. Let us understand it with an example.
Thanos has given us the responsibility to keep track of his stone collection. At first his basket is empty and whenever he collects a stone the basket has to be updated and he is not sure in which order he will collect them. He also wants to know the current status of his basket anytime he wants.
//thanosBasket holds info whether a particular stone is in his //basket or not. const thanosBasket={ Space_Stone:'NO', Reality_Stone:'NO', Power_Stone:'NO', Mind_Stone:'NO', Time_Stone: 'NO', Soul_Stone:'NO'}//We will Create functions which will set the stone state to //'YES'when it is added to basketconst addSpaceStone = (basket)=>({...basket, Space_Stone:'Yes'})
In the above function, we are taking an object ‘basket’ as input. we are using () after arrow function to directly return the resultant object. Then we are creating an object, where we are using spread operator to copy the object and modifying only one member.
const addRealityStone = (basket)=>({...basket, Reality_Stone:'Yes'})const addPowerStone = (basket)=>({...basket, Power_Stone:'Yes'})const addMindStone = (basket)=>({...basket, Mind_Stone:'Yes'})const addTimeStone = (basket)=>({...basket, Time_Stone:'Yes'})const addSoulStone = (basket)=>({...basket, Soul_Stone:'Yes'})//Once Thanos has three stones- Space, Reality and Power - his basket will look like belowaddSpaceStone(addRealityStone(addPowerStone(thanosBasket)))//{Space_Stone: "Yes", Reality_Stone: "Yes", Power_Stone: "Yes", Mind_Stone: "NO", Time_Stone: "NO", Soul_Stone: "NO"}
Here we are not modifying the original basket instead we are creating a new object which will hold the current status. Even though multiple functions are updating the basket, we don’t have to worry as we are not sharing the state but creating new objects which will hold the current state.
Referential Transparency
If Thanos can get hold of the 6 infinity stones, he will assume absolute power and it is certain that he can make a huge destruction. He used this power to reduce the world population by half. We can write a function depicting this.
function haveSixStones(){return 'absolutePower'} console.log(haveSixStones()) //absolutePower console.log('absolutePower') //absolutePower
So we can replace the function haveSixStones directly with ‘absolutePower’. It is called Referential Transparency.
Also if we take the above thanosBasket example, we can run the functions in any order and it will always return the same result. Its one of the important concept of Referential transparency. It also eliminates side-effects by creating new object every time instead of mutating the original object.
addSpaceStone(addRealityStone(addPowerStone(thanosBasket)))addPowerStone(addRealityStone(addSpaceStone(thanosBasket)))addRealityStone(addPowerStone(addSpaceStone(thanosBasket)))//all the above three will give the same result.//{Space_Stone: "Yes", Reality_Stone: "Yes", Power_Stone: "Yes", Mind_Stone: "NO", Time_Stone: "NO", Soul_Stone: "NO"}
These functions are also pure as they will give same output for a given input always and they are not modifying any object outside of its scope.
When a function is pure and if it is immutable, then Representational Transparency comes into picture. To Sum up, all the above paradigms are closely interrelated which form the basics of functional programming in Javascript.
Written by