Rust is creating copy instead of moving

181 points moderator_sux

I've seen this pattern in many crates

fn modify(mut self) -> Self {
    //do some stuff to alter it
    self // return the same object
}

It looks noice. self is moved in and moved out and novice user like me thinks that no copy is made. but in reality, 3 copies are made

struct Massive {
    a: [i128; 10000],
}

impl Massive {
    #[inline(always)]
    fn stupid(mut self) -> Self {
        println!("{:?}", &mut self.a[1] as *mut i128);

        //do some stuff to alter it
        self.a[1] += 23;
        self.a[4] += 24;

        //return the same object
        self
    }
}

fn main() {
    let mut f = Massive { a: [10i128; 10000] };

    println!("{:?}", &mut f.a[1] as *mut i128);

    let mut f2 = f.stupid();

    println!("{:?}", &mut f2.a[1] as *mut i128);
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=89e1c2e23d804a7b7b22777e77106cde

this outputs

0x7ffd78dfdf18
0x7ffd78dafd18
0x7ffd78dd6e18

which are all different which suggest that 3 different copies are made. At first, I thought different pointers are cause of different variables and data they point must have stable address but as you can see that content have different address as well which means rust is making copy of this large object each time which is very inefficient.

I can just pass &mut self in my own code but that doesn't give you noice chaining like api like this

Massive::new()
   .setA()
   .setB()
   .setC()

and many other crates out of my control use this type of API

With all this ownership information and move semantics, why is rust creating 3 copies ?

I ran the code with

[profile.release]  
opt-level = 3  
lto = true  
panic = "abort"

❯ cargo run --release  

but it still print 3 different addresses. inlining also doesn't help

Is this bug ? is copy elision not implement in Rust ?