## FunHop: Understanding Referential Transparency

In this episode of FunHop, we would try to look at what is Referential Transparency, what is substitution model and how being immutable really helps.

Referential transparency means that we can exchange the expression by its value or a value by the expression and nothing changes. Pure functions are referentially transparent. Any function f(a)=b is a pure function if for the same “a” we end up getting the same “b” without any internal or external state change.

For example the + function is a pure function
2 + 3 and

val c= 2
c + 3

would always yield the same result. There are no side effects either.

Now, let us look at Referential Transparency.

Loot at the code block below

```val x = 7
val c = x + 2
val d = c + 3
```

Now, the value of c remains 9 even if we substitue the expression with the value of x which is 7. Taking it a step further, lets look at the following code

```val x=7
val c= 7 + 2, and
val d = 7 + 2 + 3
```

As you would agree, the results would remain the same.
Hence, if the expression can be replaced by its value and vice versa AND nothing changes then it is called Referential Transparency. This model of substituting values for expressions is called Substitution Model.

Substitution model gives us a way to naturally reason code. You would observe that substitution model lends itself easily to immutability. Only when objects are immutable, we can substitute them without any concerns on the results. Ok, let us look at a more concrete example

For example, let us refer to a money class which is represented like this

```case class Money(var amt: Int) {
def add(anotherAmt: Int): Money = {
this.amt += anotherAmt
this
}
```

Aha! some weirdness here, the add method mutates the money object and returns the mutated object. Now, for the following block of code

```object RefTrans extends App {
val money1 = new Money(10)

}
```

The output is

Now going by the Referential Transparency and Substitution model, let us replace money2 by the expression for money2 which is money1.add(20)
Hence our code becomes

```object RefTrans extends App {
val money1 = new Money(10)

}
```

Now the output becomes

Weird Huh? ðŸ˜‰

This is different than what we got first. This shows that money2 expression is NOT referentially transparent. We cannot substitute the expression with its values and get the same result.

Ok, now let us change the code a little and have GoodMoney instead which DOES NOT mutate the object.

```case class GoodMoney(val amt: Int) {
def add(anotherAmt: Int): GoodMoney = GoodMoney(this.amt + anotherAmt)
}
```

Now let us start the same cycle with GoodMoney

```object RefTrans extends App {
val money1 = new GoodMoney(10)

}
```

The output is

And now let us do the substitution,

```object RefTrans extends App {
val money1 = new GoodMoney(10)

}
```

What do you expect the output to be?
Of course it is the same