This is the second chapter in a series of articles on practical Functional Programming paradigms. If you haven’t read the previous chapters you can start from here.
What does immutability mean? The definition that you can see in Wikipedia states that an immutable object is one whose state cannot be modified after it is created. Or in other words some variable that can’t change it’s value.
The first time I encountered immutability I read the definition more than once in order to make sure I’ve read it correctly. How can I program with variables that never change their values? To me this was incredibly counterintuitive.
Nowadays we should be focusing more and more on the developer experience. With that I mean that code should be written in such a manner that it will be easily understood by the next developer. And this is exactly where immutability kicks in.
The more I read about functional programming the more I understood it’s actual goal. If you think about it, people have been writing programs for a long time and a solid part of them are written in a non-functional manner.
Chances are that if you are a web developer you will encounter more programs written without the use of FP practices. So why should you be investing the time in learning about this esoteric programming paradigm?
Functional programming’s goal is to allow us to think less and write more descriptive code.
This is what I meant when I said that FP allows us to think less. When a variable is defined it is given some value and this value will never change. Period.
It will also lower the lifespan of your separate variables. This is the number of lines in which a variable is used since it’s declaration.
Much like we discussed in the previous chapter with pure functions — you won’t be able to have all of our variables immutable and this is okay.
Functional programming is not something that you should put before the quality of your code. FP’s purpose is to help us write better and cleaner code, so if your code would be much cleaner and easier to understand if you mutate a variable then so be it.
You’ve been using immutability
When we are talking about immutability we are stressing too much on the variable side of things. How we shouldn’t be reassigning values. While in fact we should be paying more attention to our functions and writing them with immutability in mind.
As you can see, those functions do not modify the caller of the function. Each of those functions return an entirely new value, without modifying the object on which they are called. The same behaviour can be observed with many other functions in the language.
The first time I encountered this I was actually a bit frustrated. What was the point of calling that function on an array for example, if it doesn’t actually modify the array I called it on?! I was always forgetting this and it was the sole purpose for a whole bunch of bugs in my programs. To be honest it took me more time than it should to understand the benefits of this approach.
Declarative vs Iterative
Some of the most basic algorithms that you will be writing as a programer include looping through data and modifying it in some manner. Maybe you want to filter it or modify values.
The orthodox way that we are all taught is to use loops and mutate objects. There is nothing wrong in that, this is how most people are doing it and they will be doing it for a long time. This approach is considered imperative. By doing things this way we give the program explicit instructions of how to do the things that we need.
Functional programming on the other hand is meant to be declarative. What does this mean? You remember how the built in functions always return a new instance? This allows us to chain them with other such functions in order to do what we normally do with loops but with far less code.
Of course, this is the most basic of the basic examples that you will see everywhere. No one is writing programs to multiply numbers, but the point is to understand how much work FP and Immutability can save you.
In reality you will probably be looping through a set of data, doing some conditional checks, then modifying the values and calculating something in the end. Let me show you how easier to read this can be compared to loops by giving the functions above some proper naming.
This could be done with less code if you just write the logic inside the filter, map and reduce functions but to show how verbose it can be I have abstracted the logic into functions. Due to the fact that those functions always return a new object, they can be chained one after another to produce such powerful results.
Every time you write a loop think if you will understand what you have written after an year. Now look at this code — no matter when you look at it it’s pretty clear what it does and in what order it does it.
Something more practical?
if you are still not convinced of how empowering immutability can be let’s turn our eyes to React. More specifically it’s integration with Redux. If you’re not familiar with Redux you might want to do some reading on that first.
The single source of truth in Redux applications is the store. This is an object which contains the current state of your application and your components will draw information from it. But you app’s state changes all the time. Users take actions on your page which require you to constantly modify your UI.
The Redux mantra, however, is to never mutate the state! Instead in your reducers you should always be returning a new object to take the place of the previous state.
In this example we add a list of weather data to the application state, so they can be listed by our components. Notice that the reducer is not just setting a property on the state, but instead returning an entirely new object. The previous state is unfolded using the
... operator and the new properties are added afterwards. This way they will overwrite the ones from the current state object.
In order to show different this in different situations, have a look at removing an item from the state. This reducer uses the
omit function from lodash to remove an item from the state and return an entirely new object.
Your first thought may be that this is slow and constantly creating and changing objects could throttle your app. It won’t — take my word for it. Some really smart guys have worked a lot in order to ensure that this doesn’t happen.
This however enables one of the most powerful features in Redux development — time travel debugging. Because at every single time, your app’s state can be resembled as an object with certain properties if we swap it with another object that adheres to the same interface we could completely modify our app’s UI.
Time travel debugging allows you to keep track of all the previous states of your app and quickly change your UI with a single click — it just swaps the objects.
With the introduction of ES6 we got the
const keyword. With it we can create variables which cannot be reassigned a different value. In fact if you instantiate a variable using const and then try to give it a different value you will receive an error.
This is something to keep in mind when dealing with arrays. You can’t directly modify the contents of the variable but you can manipulate it’s contents like this. To avoid unnecessary headache, get your team to settle down on a variable convention and stick to it.
Thank you if you’ve read so far. Hold the clap button if you found something interesting in this article!
Next we will be going into function composition and explaining some of the more complicated functional programming concepts such as currying and partial application. Stay tuned!