Do you need immutability for functional programming?

Of course immutable data structures are great, but are they necessary for FP? Short answer is: no. There's a lot of functional ideas and perspectives that can be applied even if you don't have them. And you can always make things immutable through discipline. In this episode, we explore those two ideas.

Transcript

Eric Normand: Do you need immutability for Functional Programming? In this episode, we're going to explore the question of whether it is necessary to have immutable data structures and other kinds of immutability in order to do Functional Programming.

My name is Eric Normand, and I help people thrive with Functional Programming. I hear this a lot in podcasts. Also people ask me, they get in touch with me over email or Twitter. The ones that bug me the most are in podcasts. Those bug me. It doesn't bug me to get questions, that's great.

I hear people say, "Oh, we can't do Functional Programming because we need immutability." Or, "We can't implement this algorithm in a functional way because we need mutation." Something like that.

It's troubling because immutability, immutable data structures, that's all good. There's no denying that it's a useful tool, but it is just a tool. It's not a requirement for Functional Programming.

It helps tremendously, but you can still apply a functional thinking, a functional mindset to situations where things are mutable. That still helps. I still consider all of those things to be under the realm of Functional Programming.

Just the idea that reading from a data structure that could be changing while you read it because it could come from somewhere else, it's mutable. Something else might have a hold of the same object.

Just that idea is something that's not discussed enough outside of Functional Programming. It's something that we know very intimately in Functional Programming. It's something that we talk about all the time.

Reading from a mutable data structure is an action. That's simple. We would love to be doing only calculations, and ,so we need some kind of immutable data structure to do that.

Now, I've talked about this before. I, actually, have a very pragmatic definition of immutability. It doesn't mean that the thing can't change because of some flag you've set on it, or some discipline imposed by the language or the runtime.

An example of that would be, if you could make all the fields on a class final, or there's no setters on your class, it's only getters, it's just a bunch of data, that would be a way of making something immutable.

All the objects you talked to, that you had references to, also implemented this. You could see how you could use the language's features to implement immutability.

Another thing is maybe your language gives you immutable data structures, like Clojure does, or Haskell does. That's very nice, but it is not enough of a definition because we can implement immutability just by programmer discipline.

My practical definition of immutability is, if you don't modify something, there's no code that could possibly modify it, then it is effectively immutable. It's a discipline. You could break the discipline. You could mess up and do something wrong, but it's an ideal to strive for. It is not as hard as you might think, as a discipline.

I've gone over this in another episode. The two main kinds, it's really two and a half, but it's two kinds of discipline for enforcing immutability.

One is copy-on-write, which is where every time you want to make a change to a data structure, you make a copy and then change that copy. Once you've made the change, and you release it outside of your scope, you return it, or you send it to somebody else, some other part of the code, you can't change it anymore.

Nobody can change it. You just get this one little, tiny control period where you get to modify it. That's copy-on-write. Every time you want to change something, you make a copy, and then change the copy while you're the only one that has a handle on that copy.

The second one is called copy-on-read. If you implement copy-on-write all throughout your code base, you'll be fine. That's the best way to do it. That's how Clojure does it. It does copy-on-write. That's how Haskell does it. It does copy-on-write.

Sometimes you're dealing with a library or a legacy code, or something that you don't trust. Maybe you trusted it to do the wrong thing. You know it modifies stuff. It doesn't do the copy-on-write. Since it doesn't do copy-on-write, you can't consider your data structures immutable, or anything that it touches to be immutable.

What do you do? You do copy-on-read. If you call some API function, some library function, and you get back a data structure, you can't trust that it's immutable.

The first thing you do when you get it is you make a deep copy. You make a deep copy of it. Now, you have a copy that you're going to apply a copy-on-write discipline to.

You don't have to care what this library is going to do with the thing it gave you. You just throw it away. You're like, "I have a copy of it, my own copy. I'm going to do my own thing with it."

You can now be secure that you're using immutable data again. This is all to say that there's a second answer to the question, do you need immutability to do Functional Programming?

No. You can implement it even on top of mutable things. Even on top of mutable HashMaps, mutable objects. As long as you can make copies, shallow and deep, as long as you can do that, you're fine. You can do Functional Programming.

To recap, answer one is even before you...I say before. There's a lot of interesting and useful thoughts, thought techniques, perspectives that you can apply to code that come from Functional Programming.

These thoughts, these perspectives come from Functional Programming, you can apply it to code that doesn't have immutable data. You would learn a lot about that code.

Are you doing Functional Programming when you do that, when you apply perspectives from Functional Programming? Yes, I think you're doing Functional Programming.

Answer two is, even if your language doesn't give you immutable data structures or a way of enforcing immutability, you can still do Functional Programming. You can still implement immutability using these disciplines, these copy-on-read and copy-on-write.

You're going to have to find the other episode where I talked about immutability to figure out what that half of a discipline is for immutability. It might surprise you what it is. It really is a half. It's not a whole one. It's still very useful, and it still gives you a lot of the guarantees that immutability gives you.

If you liked this episode, you found it useful, you can find all the old episodes, the previous episodes, going back for over a hundred now, I'm sure, at lispcast.com/podcast. There you'll find audio, video, and text transcripts of all the past episodes.

You'll also find links to subscribe. Just click those buttons. Subscribe any way you want, if you want it on your podcast player, you want it on YouTube. You want it just a text transcript, subscribe to that via RSS. You can do all that.

You'll also find links to social media, my email address, Twitter, LinkedIn. Just get in touch with me. A lot of the topics for these episodes come from questions and discussions that happened because of my episodes.

My name is Eric Normand. This has been my thought on Functional Programming. Thank you for listening, and rock on.

Transcript

Eric Normand: Do you need immutability for Functional Programming? In this episode, we're going to explore the question of whether it is necessary to have immutable data structures and other kinds of immutability in order to do Functional Programming.

My name is Eric Normand, and I help people thrive with Functional Programming. I hear this a lot in podcasts. Also people ask me, they get in touch with me over email or Twitter. The ones that bug me the most are in podcasts. Those bug me. It doesn't bug me to get questions, that's great.

I hear people say, "Oh, we can't do Functional Programming because we need immutability." Or, "We can't implement this algorithm in a functional way because we need mutation." Something like that.

It's troubling because immutability, immutable data structures, that's all good. There's no denying that it's a useful tool, but it is just a tool. It's not a requirement for Functional Programming.

It helps tremendously, but you can still apply a functional thinking, a functional mindset to situations where things are mutable. That still helps. I still consider all of those things to be under the realm of Functional Programming.

Just the idea that reading from a data structure that could be changing while you read it because it could come from somewhere else, it's mutable. Something else might have a hold of the same object.

Just that idea is something that's not discussed enough outside of Functional Programming. It's something that we know very intimately in Functional Programming. It's something that we talk about all the time.

Reading from a mutable data structure is an action. That's simple. We would love to be doing only calculations, and ,so we need some kind of immutable data structure to do that.

Now, I've talked about this before. I, actually, have a very pragmatic definition of immutability. It doesn't mean that the thing can't change because of some flag you've set on it, or some discipline imposed by the language or the runtime.

An example of that would be, if you could make all the fields on a class final, or there's no setters on your class, it's only getters, it's just a bunch of data, that would be a way of making something immutable.

All the objects you talked to, that you had references to, also implemented this. You could see how you could use the language's features to implement immutability.

Another thing is maybe your language gives you immutable data structures, like Clojure does, or Haskell does. That's very nice, but it is not enough of a definition because we can implement immutability just by programmer discipline.

My practical definition of immutability is, if you don't modify something, there's no code that could possibly modify it, then it is effectively immutable. It's a discipline. You could break the discipline. You could mess up and do something wrong, but it's an ideal to strive for. It is not as hard as you might think, as a discipline.

I've gone over this in another episode. The two main kinds, it's really two and a half, but it's two kinds of discipline for enforcing immutability.

One is copy-on-write, which is where every time you want to make a change to a data structure, you make a copy and then change that copy. Once you've made the change, and you release it outside of your scope, you return it, or you send it to somebody else, some other part of the code, you can't change it anymore.

Nobody can change it. You just get this one little, tiny control period where you get to modify it. That's copy-on-write. Every time you want to change something, you make a copy, and then change the copy while you're the only one that has a handle on that copy.

The second one is called copy-on-read. If you implement copy-on-write all throughout your code base, you'll be fine. That's the best way to do it. That's how Clojure does it. It does copy-on-write. That's how Haskell does it. It does copy-on-write.

Sometimes you're dealing with a library or a legacy code, or something that you don't trust. Maybe you trusted it to do the wrong thing. You know it modifies stuff. It doesn't do the copy-on-write. Since it doesn't do copy-on-write, you can't consider your data structures immutable, or anything that it touches to be immutable.

What do you do? You do copy-on-read. If you call some API function, some library function, and you get back a data structure, you can't trust that it's immutable.

The first thing you do when you get it is you make a deep copy. You make a deep copy of it. Now, you have a copy that you're going to apply a copy-on-write discipline to.

You don't have to care what this library is going to do with the thing it gave you. You just throw it away. You're like, "I have a copy of it, my own copy. I'm going to do my own thing with it."

You can now be secure that you're using immutable data again. This is all to say that there's a second answer to the question, do you need immutability to do Functional Programming?

No. You can implement it even on top of mutable things. Even on top of mutable HashMaps, mutable objects. As long as you can make copies, shallow and deep, as long as you can do that, you're fine. You can do Functional Programming.

To recap, answer one is even before you...I say before. There's a lot of interesting and useful thoughts, thought techniques, perspectives that you can apply to code that come from Functional Programming.

These thoughts, these perspectives come from Functional Programming, you can apply it to code that doesn't have immutable data. You would learn a lot about that code.

Are you doing Functional Programming when you do that, when you apply perspectives from Functional Programming? Yes, I think you're doing Functional Programming.

Answer two is, even if your language doesn't give you immutable data structures or a way of enforcing immutability, you can still do Functional Programming. You can still implement immutability using these disciplines, these copy-on-read and copy-on-write.

You're going to have to find the other episode where I talked about immutability to figure out what that half of a discipline is for immutability. It might surprise you what it is. It really is a half. It's not a whole one. It's still very useful, and it still gives you a lot of the guarantees that immutability gives you.

If you liked this episode, you found it useful, you can find all the old episodes, the previous episodes, going back for over a hundred now, I'm sure, at lispcast.com/podcast. There you'll find audio, video, and text transcripts of all the past episodes.

You'll also find links to subscribe. Just click those buttons. Subscribe any way you want, if you want it on your podcast player, you want it on YouTube. You want it just a text transcript, subscribe to that via RSS. You can do all that.

You'll also find links to social media, my email address, Twitter, LinkedIn. Just get in touch with me. A lot of the topics for these episodes come from questions and discussions that happened because of my episodes.

My name is Eric Normand. This has been my thought on Functional Programming. Thank you for listening, and rock on.