DEV Community

Cover image for Functional Programming for the Object-Oriented Developer - Part 2
Patricio Ferraggi
Patricio Ferraggi

Posted on

Functional Programming for the Object-Oriented Developer - Part 2

If you are interested in reading this article in Spanish, check out my blog The Developer's Dungeon

Hey guys, how you been? it has been a while since we take on functional programming right? you might have even thought that I lost the interest and I am learning something new, something cooler, well think again ahah.

I am still in this process and it is a long one I tell you, learning functional programming has been one of the hardest challenges I have taken in quite some time.

Today we are gonna talk about two topics that sometimes get overlooked when learning functional programming, Immutability, and Recursion. So without further ado let's begin.


Immutability

So what do we mean by immutable? let's check the formal definition first:

An immutable object is an object whose state cannot be modified after it is created. This is in contrast to a mutable object (changeable object), which can be modified after it is created

Okay... so an object can not change after it is created. That seems very strange, does it? I mean, we do this all the time, here is an example:

let john = { name:"John", age:18 };
john.name = "Patricio";
Enter fullscreen mode Exit fullscreen mode

So what is exactly wrong about this? well apart from the fact that we now have an object called john that actually refers to a different person, the rest seems to be okayish, but what happens when you start passing john around?

const newName = (person) => {
  person.name = "Patricio";
};

let john = { name:"John", age:18 };
newName(john);
Enter fullscreen mode Exit fullscreen mode

Now, the user of the newName function needs to keep in mind that the state of john has changed, it is no longer the value he originally set it to be, but a function changed it from under his fit without him knowing. This causes very small but hard to find problems when this kind of mutation is happening all over the place in very complex objects. Your code no longer works as expected when you start refactoring and moving things because the logic was dependant on the mutation of the object.

How could we fix this? here is how:

const newName = (person) => {
  return {...person, name: "Patricio" };
};

let john = { name:"John", age:18 };
const patricio = newName(john);
Enter fullscreen mode Exit fullscreen mode

Now, when we call the newName function, a new person object is returned with all the data from john but we the different name, the state of the original john object is preserved.

On functional programming languages, this behavior is enforced by default, they require a specific keyword to allow mutation on a data structure or it is impossible to mutate an object altogether. This has the following benefits:

  • Don't need to keep a mental track of the state of your objects.
  • Don't need to worry about state changing when working on multi-threaded environments, all threads will have the same values.
  • Unit testing becomes very easy as all the state that a function needs to be tested is passed through when called and the test only checks the result.

Can we do this in JavaScript? Kind of, there is no runtime feature that prevents us from modifying state all over the place, one thing we can start doing is to use const as much as we can, this will not apply to deep properties in objects but it is a start. If we wanna go deeper on this road I recommend a third-party library like Immutable JS or Mori, with these libraries we can have lists, records and other types of data structures with the certainty of immutability.

Recursion

Again, let us start by going with the formal definition:

Recursion occurs when a thing is defined in terms of itself or of its type.

Wait, what? 🤯

Recursion

In basic practical terms, this means that a function will call itself until the process is finished and it is able to exit smoothly. You might be wondering, why in the hell we would want to do that? keeping in mind what we learned about immutability, take a look at this example. We want to print the numbers from 0 to 999 in the console:

for(let i = 0; i < 1000; i++)
{
  console.log(i);
}
Enter fullscreen mode Exit fullscreen mode

Did you notice the problem with this? we didn't keep our promise of not mutating state, the variable i is changing its value with every spin of that loop. Yes, you heard me right, if we are going immutable then for-loops are a dirty business. We can agree that as long as the mutable scope is very small, we should be fine.

But what happens if we work on a purely functional programming language, how we could do that? well here enters recursion.

const sumOneAndLog = (sum) => {
  const newSum = sum + 1;
  console.log(newSum);
  if (newSum < 1000)
    sumOneAndLog(newSum);
}

sumOneAndLog(0);
Enter fullscreen mode Exit fullscreen mode

Here we define a function called sumOneAndLog which is defined in terms of itself, as long as the sum is less than 1000 it will keep calling itself and logging the next number. This is also a very common case on things like game development, where we want to run our game indefinitely until the game ends, we can calculate the state of the game and keep pushing it forward without having a global state.

One last consideration, in JavaScript this kind of behavior is not very well supported. If you would try to do very heavy recursions you would probably blow up the stack very quickly, this is due to the fact that JavaScript engines lack a feature called Tail Call Optimization which allows this to be handled without issues, a workaround is to use a something like a trampoline.


Conclusion

Today we reviewed some key features of functional programming that can make our JavaScript run much safer and be more readable, what I am aiming with this series is for you to understand that it is not a fight on which paradigm is better, they are different and they behave better in different situations.

I truly believe that a great programmer is the one who is able to write object-oriented, functional, and structured code all the same time(no mention for logic programming, sorry ahah).

If you liked this article, please share and let me know about it below in the comments, if you think there is something I missed please let me know 😄

Top comments (0)