Functional JavaScript First Steps

Avoiding Mutation Solution

Anjana Vakil

Anjana Vakil

Software Engineer & Educator
Functional JavaScript First Steps

Check out a free preview of the full Functional JavaScript First Steps course

The "Avoiding Mutation Solution" Lesson is part of the full, Functional JavaScript First Steps course featured in this preview video. Here's what you'd learn in this lesson:

Anjana demonstrates the solution to the Avoiding Mutation exercise.


Transcript from the "Avoiding Mutation Solution" Lesson

>> So let's take a look at the solutions to these avoiding mutation exercises. Again, they are in a Fork notebook, you can find by clicking that Fork link at the top of the page of the exercise. So in this solved version, and again, plenty of ways to implement these.

The main things you wanna make sure that you're doing are not using any of those mutating array methods. You might find that you wanna use some of the non mutating array methods to implement some of these. But you can also get creative and use other things, like perhaps you could use, spread syntax, this dot, dot to implement this first one, the push function.

So the push function is gonna replace that array.push method, where instead of array.push and then the element being passed in, which is gonna mess with the original array, we're gonna take a push function that's gonna take an element and the array to put it on too. And then we could use the spread syntax to take everything out of the original array into a new array that I'm just creating with this bracket syntax here, and then add on the new element.

So that's one way we could do this. But again, your mileage may vary, there are plenty of valid solutions to implement this non mutating push. Just make sure you're not adding anything on to the original array in place. And we're checking for that in these little titles. How about the update function?

So this is gonna be a new function that replaces JavaScript built-in mutating index assignment here. So we wanna replace a single value in the array at a particular index, but we don't want to change it in place, we wanna leave the array unchanged. So we can define an update function which takes in the index and the value that you wanna put there and the original array.

And in this case, I'm using some non mutating array methods, slice and concat. Which again, if we really want to force ourselves to write code the way we probably would in a pure functional language, we could create function versions of these, kind of wrap those non mutating methods in a function signature that gives me a little bit more of a functional style.

But by this point, I think we've gotten a lot of practice on that. So just to make things easier for ourselves, we can use a chain of these methods. So we can first slice off everything before the index that I wanna replace in the array. We can concatenate that with a new little array with the value that I wanna put in at that index, and then concatenate that with the slice of the rest of the array after that index.

And what we've got here with this chain of methods is actually something also a little bit pipelining, right? And this is something that we are used to doing perhaps in functional, excuse me. This is something that we're perhaps used to doing in JavaScript is chaining methods together. Where we can take the output of, again, this non mutating slice operation, and chain that into the concat operation.

So we're calling concat on the new array return there. So again, it's a similar vibe of inputs coming into one function, and then those outputs going into the next function, and so on, and so forth. It's just that here, we're cheating a little bit and using that more regular JavaScript syntax.

So challenge to the reader at home is to create some of those more functional style wrappers around some of these operations like slice and concat which even though the built-in JavaScript methods are not mutating. If we really wanna force ourselves to think about functions first, we could try to do that without using the dot method notation.

And then the pop function again, which is to replace the mutating myraid pop. We can use the slice function for example, excuse me. We can use the slice method which again does not mutate the original array, and so we can slice off everything up to the next to last element in the array.

But again, if you can implement a slice function that is going to allow us to get into more of that functional API function calls as the way that we write our code, the style of syntax that we use as opposed to this dot method. That's again, another little challenge that you can try to force yourself to do to complete this in a way that does not involve this little period here.

And then of course, there are lots of other array methods that we could create similarly, we could create non mutating functions to sort of represent the equivalent operations of. But again, that'll be left as sort of an exercise for you to stretch mind, or if you wanna come back to this in a few days or few weeks and try that that out, perhaps to just keep that muscle memory going.

Remember the brain is a muscle, you gotta use it, and if you wanna turn it into a super strong and powerful functional programmer, you got to use it in a functional style, and really force yourself to eat your functional vegetables. Even if the mutating regular JavaScript way of working with things, perhaps comes a little bit more naturally or is a little bit more what you're used to.

The immutable data structures example is here. Again, we'll just let you all kind of digest that on your own time, but I would love to know what differences did people notice? Where there are differences in the two libraries which have a very different way of working with these immutable data structures, right?

Like for example, in immutable JS, we don't even call them arrays, we call them lists. For example, there's like a new word to learn and maps instead of objects. Whereas in MRI, we're working with more typical looking regular JavaScript things. But we're using this sort of strange produce function with these little draft call backs to create new versions.

And I'll let you all dig into exactly how it works. But after having just a few minutes to glance at it, would anybody like to share some of their thoughts on differences they noticed or some of their preferences?
>> The MRI library kind of looks more like the JavaScript we already used to, right?

Sort of kinda looks more like using a regular ES6 Map Reduce function. I will just have instead of Array prototype, whenever you now have different options, for us immutable GS can look something like it something entirely new to me.
>> Yeah, so what I heard is that the MRI library looks a little bit more like regular JavaScript, which indeed is we're working with the same old JavaScript arrays and things like that.

Whereas in immutable JS, we have some new stuff to learn, like lists and maps, and some new methods like set, and size, and get things like that. And so I believe that one of the objectives of MRI was to do exactly that to make it so that functional programmers working with immutable data in JavaScript didn't need to learn any new API's.

So that they could basically work with the features of the language that they're used to. And in fact in other cases, we could actually just kind of destructor this produce function out of the MRI object. I think it's the default value exported by this library is actually the function itself.

And then we don't even have this MRI dot, and we can just work with this produce function to produce new versions of these JavaScript objects and arrays without mutating any of them in place. So that is certainly a convenient thing. However, I think immutable maybe has been around a tiny bit longer, so there may be some people out there who are already a little bit more used to working with it.

It comes from, I believe the same team that created React at Facebook. So there might be some overlap between the React programming community and the immutable users. So if you're perhaps more comfortable with that world, there might be reasons to use it there. What do we think? Are we interested in maybe trying some of these out, taking a closer look at the docs, trying them out in our own code, seeing if we can really force ourselves to never mutate data?

What is the benefit of using these data structures like these libraries instead of using the built-in features of JavaScript that allow us to kind of make sure that data can't be changed. For example, if I'm using a const with a string, for example, so that no one can ever change the value of that variable that's holding that string, or if I'm using object.freeze to lock in a particular object.

And so that is where that efficiency issue that we ran into with copying and copying, and copying! JavaScript by default, by its nature does not have these this kind of structural sharing data structures that allow us to really efficiently make lots of copies of big data structures. And so depending on what you're doing, if you're just working with little single values or perhaps very simple data structures, and not doing a tonne of transformations.

You might not run into that efficiency problem, you might not run into performance problems. And so you might be totally happy working with those built-in JavaScript features that make sure that nothing is gonna change. However, if you're doing some really big operations, you have to have some really big data structures that require lots of updates of long arrays, and things like that.

You might find that the efficiency improvements afforded by these libraries that use these techniques of persistent data structures and immutable data structures might come in handy, especially when we're working on in situations where performance is more of an issue. Yes, once again, we have not had a ton of time to dive into the world of immutable data structures, but this is an area of functional programming that I think is super fascinating.

And so I also have a talk linked at the bottom here about how immutable data structures work in detail and why they're more efficient. So if you wanna dive in more and understand a little bit more about how trees and sharing make all of this efficiency possible, you can check that out.

And there's also going to be lots of resources linked where you can read tons more about how these very fancy, very interesting, very exciting, and really performant data structures work. Are gonna be listed in the resources at the end of the workshop. Did these libraries allow us to work with kind of deeply nested data structures, so that when I create an immutable version of let's say, an array which has other arrays in it, or an object which has other objects as values in it.

Will it kind of recursively make sure to make everything all the way down immutable? That is a great question. Since I'm not a core maintainer or power user of either of these libraries, I would probably say we should definitely check with their documentation to find out how they handle those nested data structures.

But my gut understanding is yes, they will help you do that, so that you can, like let's say make an immutable list out of a nested list and still have the deeper nested lists also be locked in place. However, don't quote me on that, go to the source, and check out the docs.

They're linked in here and make sure that is something that these libraries implement. And there are tons of other libraries out there that do something similar. So again, you might wanna look around a little bit, you can search for other immutable data structures libraries in JavaScript. Or perhaps if you program in other languages too, you can look and see what libraries exist for immutable or persistent data structures in that language.

For example, there's also one for Python, at least one that I know of, and things like that. And always make sure that you dig into those docs to understand what's happening, to understand all the API, and the examples that they'll give you in the docs to see what happens when I'm working with, let's say, a deeply nested data structure.

That's a great question.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now