Accepting nested method calls with an `&mut self` receiver

Note that there is a pending RFC on this topic:

https://github.com/rust-lang/rfcs/pull/2025

I don't think that is the most reasonable desugaring, though it appears to be what the Rust compiler is currently doing. I think this is what should be done:

{
    // evaluate outer vec.
    let a = {
        // evaluate inner vec.
        let v_ref = &vec;
        Vec::len(v_ref)
    };
    let v_mut_ref = &mut vec;
    Vec::push(v_mut_ref, a);
}

In particular, even the though compiler needs to evaluate the leftmost vec first, it doesn't need to borrow it at that time; it only needs to borrow it mutably just before Vec::push() is called.

Consider this:

fn len_mut<T>(vec: &mut Vec<T>) -> usize {
    vec.len()
}

That shows that we can create a non-mut reference even though a mut reference to the object exists.

Now consider this:

fn len_then_push(vec: &mut Vec<usize>) {
    let len = vec.len();
    vec.push(len);
}

This shows that we can use a mut reference after we've used the reference in a non-mut context.

Now consider this:

fn push_len(vec: &mut Vec<usize>) {
    vec.push(vec.len());
}

This should be exactly like len_then_push(), but instead it fails to compile because vec is borrowed mutably too early.

Here's this code on play.rust-lang.org: Rust Playground

1 Like

In the RFC, there is an example illustrating a proposal to expand your RFC’s proposal. Here’s an expanded version that I think captures more of the subtly:

fn len_then_push(tmp0: &mut Vec<usize>) {
    let tmp1 = tmp0.len(); // Used as shared.
    Vec::push(tmp0, tmp1); // Used as mutable.
}

fn main() {
   // Works fine today.
   let mut vec = vec![0];
   len_then_push(&mut vec);

   // Works fine today as only one reference to `vec` is used.
   {
     let tmp0 = &mut vec;   // `vec` is mutably borrowed.
     let tmp1 = tmp0.len(); // Used as shared.
     Vec::push(tmp0, tmp1); // Used as mutable.
   }

   // Now: Fails to compile. Future: OK.
   vec.push(vec.len());

   // Now: Fails to compile. Future: OK.
   {
     let tmp0 = &mut vec; // Now: Mutable borrow. Future: reserve `vec`.
     let tmp1 = vec.len();  // shared borrow of vec. Now: fails. Future: OK.
     Vec::push(tmp0, tmp1); // Future: mutable borrow of `vec` is activated.
   }
}

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.