Mutability in Rust, and how it differs from object-oriented languages
Tags: rust, java, mutability
Published: 2020-02-04 00:26:15

---
title: Mutability in Rust, and how it differs from object-oriented languages
published: true
description: 
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/p4dk7eziqx49m5lli0ud.png
tags: rust,java,mutability
---

This post started out as a long-winded answer to a stackoverflow question. The question made me realize that there's a pretty universal way of thinking about mutability when coming from popular languages like C# and Java, and that coming to rust with this mindset often results in confusion and frustration.

I’ll be comparing and contrasting solutions to common problems involving mutability in a way that (hopefully) expresses the differences intuitively. For the non-rust examples, I'll be using Java, but these examples can be expressed similarly in other object-oriented languages.

We'll start with a simple goal—Define a `Dog` type with two fields:

- Name, which will be immutable
- Age, which will be mutable

In the first few examples, we'll avoid common idioms like getters and setters in order to keep things simple. 

Here's how we'll define our type in Java:

```java
class Dog {
    public final String name;
    public int age;
    
    public Dog(String name) {
        this.name = name;
        this.age = 0;
    }
}
```

An equivalent type in rust would look like this:

```rust
struct Dog {
    pub name: &'static str,
    pub age: usize,
}

impl Dog {
    pub fn new(name: &'static str) -> Dog {
        return Dog { name, age: 0 };
    }
}
```

In the rust example, you may notice that there's no modifier on our `name` field to suggest that we're controlling mutability in any way. This is because *rust has no concept of mutability at the field level.*

Rust takes a fundamentally different approach. If we want to modify any field on our type, we need to declare a mutable variable pointing to it. By default, all variables are immutable and you must add the `mut` modifier if you intend to mutate it:

```rust
// Declare an immutable variable
let harris = Dog::new("Harris");
harris.age += 1; // Compile error!

// Declare a mutable variable
let mut harris = Dog::new("Harris");
harris.age += 1; // No problem!
```

At first glance, it would appear as if Java provides finer-grained control over mutability than rust—If a variable's mutable, we can mutate all of its fields; if it's immutable, we can't mutate any of them. 

## Mutability and `self` parameters

Let's update our examples to make them more idiomatic. We'll make our fields private and expose methods to access or modify them.

First in Java:

```java
class Dog {
    private final String name;
    private int age;
    
    public Dog(String name) {
        this.name = name;
        this.age = 0;
    }

    public String getName() {
        return this.name;
    }

    public int getAge() {
        return this.age;
    }

    public void incrementAge() {
        this.age += 1;
    }
}
```

And our rust example:

```rust
struct Dog {
    name: &'static str,
    age: usize
}

impl Dog {
    pub fn new(name: &'static str) -> Dog {
        return Dog { name, age: 0 };
    }

    pub fn get_name(&self) -> &'static str {
        return self.name;
    }

    pub fn get_age(&self) -> usize {
        return self.age;
    }

    pub fn increment_age(&mut self) {
        self.age += 1
    }
}
```

In the rust example, the `get_name`, `get_age` and `increment_age` methods all include a `self` parameter. Like variables, parameters are either mutable or immutable. `self` differs from other parameters in how it's passed to the method: If we have a variable named `dog` and we call `dog.increment_age()`, the `dog` variable is implicitly passed to the `increment_age` method as the `self` parameter, and can access private fields declared on the type.

This is even more interesting when we consider how this works in conjunction with variables. If we have an immutable variable, and we call a method on it that takes a `&mut self`, we'll encounter a compile error because the method *requires* mutable access to our value!

```rust
// Declare an immutable dog variable
let dog = Dog::new("Harris");
dog.increment_age(); // Compile error!

// Declare a mutable dog variable
let mut dog = Dog::new("Harris");
dog.increment_age(); // This works!
```

So what happens if we declare a variable as mutable, and call a method that takes an immutable `self` parameter? In this case, the call is valid, but the method is still only granted immutable access to the `self` parameter.

To reiterate: In order to call a method that requires mutable access to `self`, the variable *must* be declared as mutable, but methods that declare an immutable `self` parameter can be called via mutable and immutable variables alike.

## Encoding mutability in return types

We're going to introduce a new field to illustrate how mutability works with more complex types. We'll add a `List` (`Vec` in rust) to our example named `friends`:

```java
class Dog {
    private final List<Dog> friends = new ArrayList<>();
    ...

    public List<Dog> getFriends() {
        return this.friends;
    }

    public void addFriend(Dog friend) {
        this.friends.add(friend);
    }
}
```

In the java example, our new `friends` field is declared `final`, which means we can never change what the field points to, *however*, we're still free to add and remove items from the list via our getter method as seen below:

```java
   Dog harris = new Dog("Harris");
   Dog buck = new Dog("Buck");
   harris.getFriends().add(buck);
```

So how would this work in rust? Let's update our example:

```rust
struct Dog {
    ...
    friends: Vec<Dog>,
}

impl Dog {
    ...
    pub fn get_friends(&self) -> &Vec<Dog> {
        return &self.friends;
    }
}
```

In our rust example, we're actually encoding mutability into the return type of our `get_friends` method! The `&Vec<Dog>` return type represents an immutable reference because it lacks the `mut` keyword. It would be a compile error if we attempted to add an item to the returned `friends` list:

```rust
let mut harris = Dog::new("Harris");
let buck = Dog::new("Buck");
harris.get_friends().push(buck); // Compile error!
```

Let's break this down:

- We declared a mutable `harris` variable 
- The `get_friends` method returns an *immutable* reference to our `friends` field
- The [Vec](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.push) type has a method named `push` which requires a mutable reference to `self`
- Our code fails to compile because the immutable reference returned by `get_friends` cannot be used to call a method that requires mutable access to `self`

So, even though our original variable was declared as mutable, we use the `get_friends` method to hide access to our list behind an immutable reference. Consequently, it's a compile error if we attempt to mutate it.

As an exercise, let's say we wanted the `get_friends` method to provide mutable access to the the returned `friends` reference. Take a moment to consider what we'd need to change.

Have an idea? Here's the answer:

```rust
pub fn get_friends(&mut self) -> &mut Vec<Dog> {
        &mut self.friends
    }
```

To summarize, we had to:

- Declare our `self` parameter as mutable,
- Declare the return type as mutable, and
- Return a mutable reference to our list

We can now modify the `friends` list via our `get_friends` method! Whether or not we'd ever want to do this in practice is another question.


## Conclusion

Mutability in rust is very different from what most people are used to, and it can take some time for it to sink in. Once it does, however, it becomes an incredibly powerful way to enforce guarantees that aren't possible in most languages. It's also a fundamental part of the language, working in concert with other language features to achieve a unique combination of safety and performance.

### A quick note about rust idioms

The rust examples aren't particularly idiomatic, but that was done for the sake of clarity and simplicity. Perhaps I'll touch on interesting rust idioms in a separate post!