07 - SOLID: Liskov Substitution Principle
Functions that use pointers or reference to the base classes must be able to use objects of derived classes without knowing it.
I think the hardest concept to grasp in functional SOLID principles is the Liskov Substitution Princple. When I first started reading about SOLID I wasn't exactly sure if it was principles that was only applied to OOP or if it could be applied to FP. I knew that some of it made sense in the FP context, but not all. Just to be sure that I was on the right path, I consulted with my mentor who said that all of SOLID can be applied to FP. So with this confirmation I went on digging about how I could apply LSP in FP.
The original definition by Barbara Lsikov states:
What is wanted here is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.
I don't know about you but this sounds like a lot of nonsense to me. It is pretty hard to understand even in OOP terms, so I was a little concernced about how I can figure this concept out in FP terms. One thing that I was sure of was that it made me comfortable knowing there are plenty of other people who like me, who also needed an ELI5 explanation.
In OOP land, what LSP means is to be able to replace the base class with its subclass without any issues. In Elixir we can think of it as the ability to add any new module which implements the behaviour without altering any of the other module properties. So basically when we have code that expects a specific Behaviour or Module ensure you are only using function calls defined in that Behaviour.
Here in this example we can be sure that we have the ability to utilize and interchange between any of these display behaviours on the shape without having issues.
I would like to reiterate that when it comes to LSP in FP, rather than having the ability to substitute subclasses with base classes, we want to be able to substitute one Behaviour module with another while still having an expectation that the second module will behave in the same way as the first.