Why can I call a mutable method from a non-mutable reference?

I have stumbled upon code similar to this one and it leaves me pretty confused:

use std::fs::File;
use std::io::{self, Write};

struct Foo {
    file: File,
}

impl Foo {
    fn bypass_nonmut(&self, data: &[u8]) -> io::Result<usize> {
        (&self.file).write(data)
    }
}

std::io::Write.write() takes a mutable reference to self. My method bypass_nonmmut() only provides a non-mutable reference to the object owning the File instance, which should make it impossible to call write() on it. Yet using the (&self.file) trick I can call it regardless.

Could someone explain to me how this is possible?

1 Like

There is an implementation of Write for &File, which is what's being used by your method.

1 Like

Rust references are primarily about being shared vs exclusive.

Mutability is only a secondary effect (&mut isn't a great name because of that, it should have been something like &excl). For example, atomic numbers can be mutated via shared reference. Types with interior mutability can be mutated via shared reference. &File can be written to, because the OS supports shared access.

2 Likes

Ahhh that makes sense. Files are safe to access concurrently, so there is no reason to limit their access to be unique. The Write and Read interfaces mandate a unique reference, but implementing them on &File provides a way to perform concurrent access anyway through a zero-cost indirection.

Thanks for the explanation, I can sleep tonight!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.