How come by default impl methods take ownership via &self?

struct Area
{
    width:      f64,
    height:     f64,
    is_trig:    bool,
}

impl Area
{
    fn square(length: f64) -> Self
    {
        Area{width: length, height: length, is_trig: false}
    }

    fn cal(&self) -> f64
    {
        self.width * self.height * if self.is_trig == true {0.5} else {1.}
    }
}

fn main()
{
    let square      = Area::square(10.);
    let rect        = Area{width: 20., height: 30., is_trig: false};
    let trig        = Area{width: 20., height: 30., is_trig: true};

    println!("Square: {}\nRectangle: {}\nTriangle: {}", square.cal(), rect.cal(), trig.cal());
}

In the code above,

fn cal(&self) -> f64 with this function, how come by default using the self keyword takes ownership rather than copying the data? Isn't this data stored all on the stack?

There may be some copying of types that impl Copy, like f64. But what makes you think something is taking ownership?

1 Like
fn cal(&self) -> f64
    {
        self.width * self.height * if self.is_trig == true {0.5} else {1.}
    }

if I wrote self instead of &self, this method will take ownership of the value and I can't use this function anymore.

That's what taking ownership means. If you want it to remain valid, you have to opt-in to that with a #[derive(Copy, Clone)]

Rust needs to let the programmer decide whether their method should consume the object, take an exclusive reference, or a shared reference. Each of these cases needs its own syntax to specify it, and in rust those are self, &mut self, and &self; none of them is really “default.”

3 Likes

@alice @2e71828 I understand this but like why by default does it take ownership over just copying the data?

Isn't this the question you have asked already?

I think I forgot me asking.

Being Copy actually increases your chance of increased memory usage, because it allows the compiler to transparently create extra copies of your data. And this, I presume, is why it's not default.

That's certainly not the only reason. It can also cause problems if you have a library and forgot to opt-out, because then adding a non-Copy field breaks the struct being Copy, which would be a breaking change to the library. However if it is opt-in, then this mistake is much harder to make.

2 Likes

This is still not true, as I also mentioned in the other thread. The compiler is not stalking your code looking for places to inject unnecessary copies. If you write code that requires a copy, Copy allows the compiler to insert it, but not implementing Copy in that case would make the code not compile. I'm aware of this exception but it is not generally what people are talking about when they say Copy allows the compiler to make copies for you.

!Copy is not an effective guard against unnecessary copies.

Here's another recent thread about Copy

1 Like