Are exposed references immutable?

I have a noob question about references that are exposed.

In c++ I could expose data elements with const & and (under normal conditions), the user of the library would not be able to modify the referenced object.

I think the same can be done in Rust, but I am not 100% sure. My question is whether a client module can gain mutable access to owned data that is exposed as a reference.

The gist below demonstrates that it cannot gain such access. exactly as I expected But I do not know enough about Rust to be certain. Is there a (safe) way for the client module to change the value of 'Line..point.x'?

// a pattern to prevent clients from modifying
mod sub {
    // in real code the point object is really to small to clone
    // but here we use it to demontrate an idea
    #[derive(Clone)]
    pub struct Point {
        pub x: i32,
        pub y: i32,
    }

    impl Point {
        pub fn new(x: i32, y: i32) -> Self {
            Point { x, y }
        }
    }

    pub struct Line {
        from: Point,
        to: Point,
    }

    impl Line {
        pub fn new(from: Point, to: Point) -> Self {
            Line { from, to }
        }
        
        pub fn from(&self) -> &Point { &self.from }
    }
}

use sub::*;

fn main() {
    let p = Point::new(0, 0);
    let q = Point::new(10, 10);
    // assume we want line to be mutable for some reason
    // note thate we transfer ownership of p and q here
    let mut line = Line::new(p, q);
    println!("before: {},{}", line.from().x, line.from().y);
    // then the client is able to change the from point because it is public
    let f : &mut Point = &mut (line.from());
    // this is the line I do not want to be possible, 
    // currently it does not not compile
    f.x = 20;
    println!("before: {},{}", line.from().x, line.from().y);
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
warning: variable does not need to be mutable
  --> src/main.rs:38:9
   |
38 |     let mut line = Line::new(p, q);
   |         ----^^^^
   |         |
   |         help: remove this `mut`
   |
   = note: `#[warn(unused_mut)]` on by default

error[E0596]: cannot borrow data in a `&` reference as mutable
  --> src/main.rs:41:26
   |
41 |     let f : &mut Point = &mut (line.from());
   |                          ^^^^^^^^^^^^^^^^^^ cannot borrow as mutable

For more information about this error, try `rustc --explain E0596`.
warning: `playground` (bin "playground") generated 1 warning
error: could not compile `playground` due to previous error; 1 warning emitted

Yes, immutable references really are immutable. As your code is written, there is no way to mutate the from point of a Line.

Be aware that in some circumstances it is possible to mutate through an immutable reference when the target type is something special such as a Mutex or RefCell. This is called interior mutability, and I've written a blog post about it here. Another good blog post about it can be found here. However, this does not apply to you, because you aren't using any of the special types that allow interior mutability.

2 Likes

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.