As you learn more about programming, you’re going to come across weird and wacky terms. One of the terms I want to cover today is mutability and its complement, immutability. Let’s get into it!
To quickly summarize, mutability is the ability of some data to be changed or modified. Mutability is typically only possible if the data has some way of accessing its internal structure—either directly through fields or indirectly through methods or operators. Without the ability to access the internal structure of the data, the data cannot be changed and is therefore immutable. Examples of mutable data include common data structures like lists, arrays, and maps. On the other hand, typical examples of immutable data include Strings and numbers.
With that out of the way, let’s take a deeper dive.
Table of Contents
Types of Data
In imperative programming, we store variables by type. For example, if we want to store an integer, we usually have to declare our variable of type integer. Or at the very least, the language is able to infer that type.
As we discussed previously, there are ways to categorize data types. For instance, in many programming languages, variables have two types: their static type and their dynamic type. As it turns out, there are some other categorizations as well, such as mutability and immutability. Both of which, we’ll cover today!
That said, as a quick summary, mutability refers to a variable’s ability to change. Therefore, a variable is said to be mutable if its value can be updated or replaced. In contrast, a variable is said to be immutable if its value cannot be updated or replaced.
Mutability, in general, describes data that is able to be changed. For example, an array is usually mutable because you can change the elements inside it. In contrast, strings are usually immutable to stop you from changing the individual characters. These rules aren’t universal, but they hold true for many mainstream languages.
That said, what actually makes a data type mutable? In object-oriented programming, data is only mutable if a method or operator exists that lets you modify the internal fields or the internal fields are exposed and mutable—a recursive definition.
A great example of mutability is a list from Python. To make changes to it, you can call a variety of methods, such as
pop(). Each of these methods update the list in place with changes being seen on the original list after each method call.
On the flip side, a great example of an immutable data type is the String type from Java. In Java, all the methods you have available to you for strings don’t actually modify or “mutate” the strings. Instead, methods like
toLowerCase() actually return a new string. In fact, without an introspection library like reflections, there is no way to modify a string in place, and I certainly wouldn’t recommend you try.
Overall, I’m not sure of the ratio of mutable to immutable objects, but I imagine most objects in the wild are mutable. Which raises the question: what’s the point of mutability?
What’s the Purpose of Mutability?
It might seem weird given how prolific mutability is, but you should really question its purpose. After all, if I were to ask my students the point of mutability, they would probably get pretty mad. In their experience, mutability is a huge pain. Just bring up the phrase “NaturalNumber.”
In all seriousness though, mutability seems convenient at times, but at other times it can be a huge pain. If that weren’t true, I wouldn’t have written multiple articles about the issues that come from mutability:
- How to Swap Java Reference Types in a Method
- What Is Aliasing in Computer Science? Why Does It Happen? And Is It Bad?
- Be Careful When Copying Mutable Data Types
- Improve Code Readability by Using Parameter Modes
So, why deal with all that stress? Well, functional programmers would agree with you. In fact, they go as far as to not track state at all (or at least to avoid side effects when possible). Why bother when life is easier when you don’t have to trace every line up to the line you care about?
Of course, life is not that simple. A stateless world isn’t necessarily easier to work with, and in some cases, it’s not possible. Computers in their most trivial form typically require state—even vending machines which rely on state machines:
With that said, the general issue with immutable data is the need for mutation. This is why folks frown so heavily on concatenation in languages like Java because immutable strings have to be copied and merged. Wouldn’t it be easier (ignoring the security issues) to just modify our string in place?
Likewise, mutability tends to map onto the real world better. When I drink a can of pop, I consider it the same can of pop until it’s empty. It doesn’t suddenly become a new can of pop just because some of the fluid inside is gone. A similar statement could be made about myself. I haven’t gained a new identity just because I drank some pop (and I don’t have time to be contemplating a Ship of Theseus style existential crisis). As a result, mutability tends to make a lot of intuitive sense.
With all that said, mapping programming onto the real world is always a challenge that invites all of the messiness of the real world into the code. So, be ready to handle it. In the meantime, I hope you enjoyed this article. See you next time!
2023 is the year of my 29th birthday and boy have I started to feel it. Anyway, here's the usual annual list post.
Comparing strings in Java is always a nightmare, but did you know using == can sometimes work? Yeah, say hello to more nightmare fuel.