AlgoDaily

Mutability Vs Immutability

Read at your own pace. Code execution, quizzes, progress tracking, and the AI tutor are available in the interactive view with JavaScript enabled.

Introduction

Understanding Mutability & Immutability in Programming

In the realm of software development, especially when dealing with object-oriented or functional programming paradigms, the concepts of mutability and immutability play a pivotal role. They influence not just how data is handled, but also the overall robustness, efficiency, and clarity of the code.

Mutability and immutability are key concepts in both object-oriented and functional programming. This refers to the ability of an object to change its internal state.

Mutability & Immutability, What’s the Difference?

Mutability & Immutability, What’s the Difference?

Mutable Objects: The Malleable Entities

Mutable objects, as the name suggests, are flexible. They can be altered or 'mutated' after they've been initialized. This means that their internal state or data can change over time, often in response to program actions or operations.

For example, consider a list in Python. You can add, remove, or modify its elements after its creation, making it a classic example of a mutable object.

Advantages: - Flexibility: Mutable objects can be adjusted on-the-fly, making them adaptable to dynamic data or changing requirements. - In-Place Modifications: Since you can change the content directly, there's no need to create a new object every time a change is needed. This can be memory-efficient for large data structures.

Drawbacks: - Thread Safety: Mutable objects can be tricky in multi-threaded environments. Simultaneous modifications by different threads can lead to unpredictable behaviors or data corruption. - Predictability: Continuous changes to an object can make the flow of data harder to trace and debug.

Immutable Objects: The Constants in Chaos

Contrastingly, immutable objects are set in stone. Once they're created, their state remains unchanged. Any operation that seems to alter them actually creates a new object with the desired changes, leaving the original untouched.

Take the example of strings in many programming languages. When you "modify" a string, you're often creating a new one while the original remains unaltered.

Advantages: - Thread Safety: Since the state of an immutable object never changes, there's no risk of data corruption from simultaneous modifications. This makes them inherently safe in concurrent or parallel processing scenarios. - Predictability & Readability: With no unexpected changes, the behavior of immutable objects is easier to understand, making the code more readable. - Security: Immutable objects can't be tampered with, ensuring data integrity.

Drawbacks: - Memory Overhead: Every "modification" leads to a new object, which can be memory-intensive for large data structures or frequent changes.

Getting It?

Simply put, a mutable object can have its internal state changed aka 'mutated', whereas an immutable object cannot be changed once created.

Strings are an example of objects that are immutable. They are frequently used in programming to improve readability and runtime efficiency. These objects are also advantageous because they are by nature, thread-safe, easier to understand and reason about, and provide greater security in comparison to mutable objects.

Ultimately, whether an object is mutable or immutable can greatly influence how it is used and the overall performance of your code.

So, should I use mutability or immutability? Let's dig a little deeper and see what situations are preferable for both.

True or False?

True or False: You can change an immutable object after it has been created.

Mutability, When and Why Should It?

Mutability, When and Why Should It?

Various factors can influence whether mutable or immutable objects are used in programming. Consider the following reasons why programmers may prefer mutability: - Speed & Efficiency: Some developers may choose mutable objects because they are faster and more efficient. However, on the downside this may result in more time spent fixing bugs in the long run. - Convenience: Mutable objects often require less code and fewer variables in the short run. - Necessity: In some cases, using mutation is unavoidable, particularly when dealing with user input or UI modifications.

Overall, mutable objects may be more appropriate in situations where speed is a top priority, such as game development or real-time stock market software. In most cases, the risks of mutation outweigh the benefits. However, for small and simple programs, the risks may not be significant enough to warrant consideration of immutability.

Immutability, When and Why Should It?

Immutability, When and Why Should It?

Immutable objects offer a number of advantages over their mutable counterparts. Let's explore some of the reasons why programmers might prefer immutability: - Readability: Since variables remain constant, code is easier to understand. Extensive commenting is no longer required. - Speed & Efficiency: We spoke earlier about the advantage of mutability in the short-run, however using immutability improves speed and efficiency in the long-run. While writing immutable code requires more effort, it is easier to manage and update. Have you ever heard the expression "short term pain, long term gain?" That is immutability in a nutshell. - Traceability: This is made easier because it is possible to identify how and where data changes in the code, as well as which parts of the application need to be reloaded with each change. - Safety & Validity: Once an immutable object's state is verified, its safety and validity are guaranteed because no background process can change it without the developer's knowledge. - Caching: The immutability of the values of immutable objects makes them ideal for caching and simplifies testing and debugging.

Now that we've established that, let's look at mutability and immutability in the context of a few differing programming languages.

State Change Decision Lens

Before we jump into language-specific examples, anchor the tradeoff visually: mutation changes an existing object, while immutability produces a new value and leaves the old one intact.

Notice the interview framing: mutable objects can be faster and convenient, but immutable objects make state changes easier to reason about, test, cache, and share safely.

State Change Decision Lens

Mutation Tradeoff Map

Before jumping into language examples, keep the decision simple: mutation changes an existing object, while immutability preserves the old value and creates/uses a new one.

Use the visual as a quick interview checklist: choose mutability when controlled in-place updates matter; choose immutability when predictability, safety, caching, or debugging matter more.

Mutation Tradeoff Map

When to Use Which

True or False?

*True or False: *Using mutability improves the readability of you code.

Python

Python

Mutable Data Types

Some examples of mutable data types in Python are as follows: - List - Dict - Set - Byte Array - User-defined classes.

Mutable Example

Let's say we want to create a list of our favorite movies.

fav_movies = ["American Gangster", "Bohemian Rhapsody", "Shutter Island", "The Intouchables"]

Now, let's say you go to the movies to see the new avatar movie and decide it's your new favorite. We can easily add this to our list by putting it at the first index.

fav_movies[0] = "Avatar: The Way of Water"

When we call our list, we get the following result:

fav_movies
# ['Avatar: The Way of Water','Bohemian Rhapsody','Shutter Island', 'The Intouchables']
Immutable Data Types

Some examples of immutable data types in Python are as follows: - Str - Int - Float - Complex - Tuple - Frozen Set - Boolean.

Immutability libraries such as dataclasses and namedtuples can be used to make mutable classes immutable.

Immutable Example

Let's say we want to define a string that contains our now favorite movie Avatar.

new_fav = "Avatar"

But then you realize you forgot to specify it was "Avatar 2"

new_fav[7] = "2"

Because a string is immutable, the result is a TypeError.

```py
# Mutable Data Types Example

# Creating a list of favorite movies
fav_movies = ["American Gangster", "Bohemian Rhapsody", "Shutter Island", "The Intouchables"]

# Modifying the first movie in the list
fav_movies[0] = "Avatar: The Way of Water"

# Displaying the modified list
print(fav_movies)  # ['Avatar: The Way of Water','Bohemian Rhapsody','Shutter Island', 'The Intouchables']

# Immutable Data Types Example

# Creating a string for the favorite movie
new_fav = "Avatar"

# Trying to modify the string (will result in a TypeError)
try:
    new_fav[7] = "2"
except TypeError as e:
    print(f"Error: {e}")

if __name__ == "__main__":
    pass

```

Java

Java

Mutable Data Types

Some examples of mutable data types in Java are as follows: - Array - ArrayList - HashMap - HashSet - LinkedList - TreeMap - TreeSet - VectorStringBuilder - java.util.Date - java.util.Calendar.

Mutable Example

The following is an example of mutability in Java.

class MutableEx {
   private int x;

   public MmutableEx(int, x) {
    this.x = x;
   }
   public void setX(int x) {
    this.x = x;
   }
   ...
}

The class 'MutableEx' is mutable because we can change the value of the attribute x using the setter we created.

Immutable Data Types

Some examples of immutable data types in Java are as follows: - String - Integer - Long - Float - Double - Short - Byte - Character - Boolean - java.math.BigInteger - java.math.BigDecimal - java.time.* classes (such as LocalDate, LocalTime, LocalDateTime, and Instant).

It's worth noting that some mutable classes can be made immutable by using specific methods or constructors, or by using immutability libraries such as Guava and Apache Commons Lang.

Immutable Example

The following is an example of immutability in Java.

class ImmutableEx {
   private int x;

   public ImmutableEx(int, x) {
    this.x = x;
   }
   public int getX() {
    return.this.x;
   }
}

The class 'ImmutableEx' is immutable because if we create an object from this class we cannot change the value of the attribute x of this object.

```java
import java.util.*;

public class Main {

    // Mutable Example class
    static class MutableEx {
        private int x;
       
        public MutableEx(int x) {
            this.x = x;
        }
       
        public void setX(int x) {
            this.x = x;
        }
        
        public int getX() {
            return this.x;
        }
    }

    // Immutable Example class
    static class ImmutableEx {
        private final int x;
       
        public ImmutableEx(int x) {
            this.x = x;
        }
       
        public int getX() {
            return this.x;
        }
    }

    public static void main(String[] args) {
        // Demonstrating mutable class
        MutableEx mutableObj = new MutableEx(5);
        System.out.println("Mutable Object's Initial Value: " + mutableObj.getX());
        mutableObj.setX(10);
        System.out.println("Mutable Object's Modified Value: " + mutableObj.getX());

        // Demonstrating immutable class
        ImmutableEx immutableObj = new ImmutableEx(5);
        System.out.println("Immutable Object's Value: " + immutableObj.getX());
    }
}

```

Same Idea, Different Defaults

Python and Java use different syntax, but the mental model is the same: some values allow in-place edits, while others force you to create or assign a new value.

When scanning a language during interviews, ask: Can this object be changed through this reference, or does the operation produce another value?

Same Idea, Different Defaults

Language Pattern Snapshot

Python and Java use different syntax, but the mental model is the same: containers and custom objects often mutate, while many primitive/value-like types do not.

In the visual, focus on the operation result: did we update the same object, create a new value, or block the change entirely?

Language Pattern Snapshot

Defensive Copying

Defensive Copying

In Java, making fields private final is a great start, but it is not always enough.

Why? Because final means the variable cannot point to a different object. It does not always mean the object it points to cannot change.

This matters most when an object stores a mutable field, like an ArrayList, array, Date, or HashMap.

A common solution is defensive copying: - Copy mutable input in the constructor. - Return a copy from the getter. - Avoid setters for fields that should not change.

In the example below, MovieWatchList is immutable from the outside because callers never receive its real internal list.

Defensive Copying

```java
import java.util.*;

public final class MovieWatchList {
    private final List<String> movies;

    public MovieWatchList(List<String> movies) {
        // Copy the input so outside code cannot mutate our internal state
        this.movies = new ArrayList<>(movies);
    }

    public List<String> getMovies() {
        // Return a copy so outside code cannot mutate our internal state
        return new ArrayList<>(movies);
    }
}

class Main {
    public static void main(String[] args) {
        List<String> original = new ArrayList<>();
        original.add("Shutter Island");

        MovieWatchList list = new MovieWatchList(original);

        original.add("Avatar: The Way of Water");

        System.out.println(list.getMovies());
        // [Shutter Island]
    }
}
```

True or False?

True or False: In Java, declaring a field as final always makes the object stored in that field immutable.

Common Types

True or False?

*True or False: * In both Java and Python, strings are considered an immutable data type.

Javascript

JavaScript

Mutable Data Types

In JavaScript, some of the mutable data types include: - Object - Array

Mutable Example

Let's assume we want to create an array of our favorite movies.

let favMovies = ["American Gangster", "Bohemian Rhapsody", "Shutter Island", "The Intouchables"];

Now, let's imagine you've just watched the new Avatar movie and you've decided it's your new favorite. We can easily add this to our list by placing it at the first index.

favMovies[0] = "Avatar: The Way of Water";

When we log our array, we get the following result:

console.log(favMovies);
// ['Avatar: The Way of Water','Bohemian Rhapsody','Shutter Island', 'The Intouchables']
Immutable Data Types

In JavaScript, some examples of immutable data types include: - String - Number - Boolean - undefined - null

While JavaScript doesn't have in-built immutability libraries like Python, there are third-party libraries such as Immutable.js that can be used to achieve immutability.

Immutable Example

Let's say we want to define a string that represents our new favorite movie, Avatar.

let newFav = "Avatar";

But then you realize you forgot to specify it was "Avatar 2". Trying to change a character in a string will lead to an error in strict mode.

newFav[6] = "2";

Because a string is immutable in JavaScript, attempting to modify it this way won't have any effect and will throw an error in strict mode.

```js
// Mutable example
let favMovies = ["American Gangster", "Bohemian Rhapsody", "Shutter Island", "The Intouchables"];

// Assume you've just watched the new Avatar movie and decided it's your new favorite.
favMovies[0] = "Avatar: The Way of Water";

console.log("Updated Favorite Movies List:");
console.log(favMovies);
// ['Avatar: The Way of Water','Bohemian Rhapsody','Shutter Island', 'The Intouchables']

console.log("\n"); // For spacing

// Immutable example
let newFav = "Avatar";

// Uncommenting the line below won't have any effect and will throw an error in strict mode
// newFav[6] = "2"; 

console.log("Favorite Movie:");
console.log(newFav);

```

C++

C++

Mutable Data Types

In C++, mutable container types include: - Vector - Map - Set - Deque - Array - List

Mutable Example

Let's say we wish to create a vector of our favorite games.

#include <iostream>
#include <vector>

int main() {
    std::vector<std::string> favGames = {"Halo", "Age of Empires", "The Witcher", "Civilization"};

    // Now, let's assume you've just played the new game "Cyberpunk" and you've decided it's your new favorite. 
    // We can easily add this to our list.
    favGames[0] = "Cyberpunk 2077";

    // Print the updated list
    for(const auto& game : favGames) {
        std::cout << game << std::endl;
    }

    return 0;
}
Immutable Data Types

In C++, the concept of immutability is not tied to specific data types but rather achieved using const qualifier.

Immutable Example

Let's say we have a string to store the title of a book you just read, Dune.

#include <iostream>
#include <string>

int main() {
    const std::string favBook = "Dune";

    // Now, if you try to change the book title to "Dune 2", you'll encounter a compilation error.
    // favBook = "Dune 2"; // This line will cause a compile-time error

    std::cout << favBook << std::endl;

    return 0;
}

Because the string is declared as const, it becomes immutable and attempting to modify its value will result in a compilation error.

```cpp
#include <iostream>
#include <vector>
#include <string>

int main() {
    // Mutable example
    std::vector<std::string> favGames = {"Halo", "Age of Empires", "The Witcher", "Civilization"};

    // Assume you've just played the new game "Cyberpunk" and decided it's your new favorite. 
    favGames[0] = "Cyberpunk 2077";

    std::cout << "Updated Favorite Games List:" << std::endl;
    for(const auto& game : favGames) {
        std::cout << game << std::endl;
    }

    std::cout << std::endl; // For spacing

    // Immutable example
    const std::string favBook = "Dune";

    // Uncommenting the line below will cause a compile-time error since the string is immutable
    // favBook = "Dune 2"; 

    std::cout << "Favorite Book: " << favBook << std::endl;

    return 0;
}
```

Reference Versus Value Guardrails

JavaScript and C++ add one more useful layer: immutability can depend not only on the type, but also on how the value is referenced or declared.

In JavaScript, arrays and objects remain mutable even when the variable binding is protected. In C++, const is the guardrail that prevents modification through that declaration.

Reference Versus Value Guardrails

Cross-Language Takeaway

After seeing Python, Java, JavaScript, and C++, the main skill is not memorizing every type. It is learning to ask: where is mutation allowed, and what keyword/API prevents it?

This is especially useful in interviews because mutability bugs often hide behind shared references, setters, arrays, objects, and containers.

Cross-Language Takeaway

Conclusion

Conclusion

In this tutorial, we defined the distinction between mutability and immutability in the contexts of several programming languages.

To Mutate or Not to Mutate?

The choice between mutable and immutable objects isn't black and white. It often depends on the specific requirements of your application, performance considerations, and the programming environment.

  • Performance-Intensive Tasks: If your code involves heavy data manipulation, mutable objects might offer better performance due to in-place modifications.
  • Concurrency & Parallelism: In multi-threaded applications, immutability can be a boon, reducing the complexities of handling shared data.
  • Data Integrity & Security: For scenarios where data integrity is paramount, such as financial transactions or cryptographic operations, immutability can offer added security.

Understanding the nuances of mutability and immutability is crucial for any developer. It enables informed decisions, ensuring that the code is efficient, robust, and fit for purpose. Before choosing, always weigh the pros and cons in the context of your specific application.

One Pager Cheat Sheet

One Pager Cheat Sheet

  • In software development, the concepts of mutability and immutability, essential to both object-oriented and functional programming, refer to an object's ability to change its internal state, impacting the robustness, efficiency, and clarity of the code.
  • The article describes the differences between mutable and immutable objects in programming, with mutable objects being changeable after initialization and offering flexibility and memory-efficiency, but issues with thread safety and predictability, and immutable objects being unchangeable after creation providing thread safety, predictability, readability, and security, but can lead to memory overhead; strings are given as an example of immutable objects.
  • Immutable objects are defined as those whose state cannot be modified after creation, any changes seeming to alter the state actually creates a new object, with the original remaining unchanged, providing benefits in situations that need predictability, readability, thread safety, and security. This trait distinguishes them from mutable objects, which can have their state changed post-creation.
  • Programmers may prefer mutable objects for their speed & efficiency, convenience and in cases of necessity, like user input or UI modifications, but despite such benefits, mutable objects can lead to higher risk of bugs, making them less suitable except in instances requiring maximum speed or for small simple programs.
  • The advantages of immutability in programming include improved readability, long-term speed and efficiency, easier traceability, better safety and validity, and ideal caching capabilities due to values of immutable objects being unchangeable without the developer's knowledge.
  • - Use mutation when controlled in-place updates matter; prefer immutability when predictability and safety matter more.
  • - Mutable favors controlled in-place updates; immutable favors predictable, safer state.
  • The image illustrates the concepts of immutability and mutability in programming, with functional programming favoring immutability for reduced bugs and easier reasoning, and imperative programming utilizing mutability for potentially better performance and more natural modeling.
  • The statement is false as mutability can often result in complex and error-prone code with unexpected side effects, especially in large codebases or among multiple developers, whereas immutability enhances readability and predictability as variables maintain their values, making the code more understandable, manageable, and less prone to bugs.
  • In Python, mutable data types such as list, dict, set, byte array, and user-defined classes can be modified after their creation, as demonstrated by adding a new favorite movie to a list, while immutable data types like str, int, float, complex, tuple, frozen set, boolean cannot, resulting in a TypeError when trying to change part of a string.
  • In Java, mutable data types such as Array, ArrayList, HashMap, and java.util.Date allow their values to be changed, while immutable data types like String, Integer, Long, and java.math.BigInteger do not; although some mutable classes can be converted to immutable using methods or libraries like Guava or Apache Commons Lang.
  • - Across languages, classify values by whether operations mutate the existing object or create/assign a replacement value.
  • - Across languages, classify an operation by whether it mutates the same object or produces/prevents a new value.
  • The image provides a comparison between mutable and immutable data types in Python, Java, and JavaScript, highlighting differences such as lists and dictionaries (Python), arrays and hashmaps (Java), and objects and arrays (JavaScript) being mutable, while strings and tuples (Python), strings and primitives (Java), and strings and numbers (JavaScript) are immutable.
  • In both Java and Python, strings are immutable, meaning they cannot be changed once created, differing from mutable data structures like lists or arrays; this feature enhances security by ensuring string content cannot be altered unintentionally.
  • In JavaScript, mutable data types like Object and Array can be altered, as demonstrated by changing an element in an array, while immutable data types such as String, Number, Boolean, undefined, and null cannot be changed, which is shown through the failed attempt to modify a string.
  • In C++, mutable container types include Vector, Map, Set, Deque, Array, and List, which can have their values altered, while immutability is achieved using the const qualifier to prevent any changes to a value.
  • - JavaScript protects primitive values and can protect bindings; C++ uses const to make mutation illegal through a declaration.
  • - In any language, look for the mutation gate: shared reference, setter, container method, or immutability keyword/API.
  • The distinction between mutability and immutability in programming languages is crucial for developers and should be chosen based on specific needs: mutable objects may improve performance for performance-intensive tasks, immutability can simplify data handling in concurrency and parallelism, and ensure data integrity and security in sensitive operations.
Open interactive view →