Unable to return struct type in unary negation operator

Technically a 2 fold question.

I have a struct Point which does not derive Clone or Copy and am attempting to add a unary negation operation like below

impl<'a> std::ops::Neg for &'a Point {
    type Output = Point;

    fn neg(self) -> Self::Output {
        Point {
            x: -self.x, // f64
            y: -self.y, // f64
            z: -self.z, // f64
        }
    }
}

However, even after specifying the output type, using the operator returns a &Point in practice. This works correctly for other operations such as Add or Sub

let p = Point { x, y, z };
let neg = -p; // this is a &Point

Questions are

  1. Are there notable performance improvements for defining reference operations instead of copying?
  2. What am I doing wrong for negation that somehow works for other operations?

Are you missing an &?

Edit: regarding question 1.

In my Limited experience, for small POD types the compiler will replaced/introduce references as it likes, and will inline many simple functions, so this is not too important.
But, as.always, measure your use-case.

Can you provide a playground example demonstrating that?

You seem to be thinking of references as "not copying". Rust's references are for "not owning", which is a different thing with very important implications.

You should not use references to merely avoid copying, because they don't just add a level of indirection, but they also add memory management restrictions and bind items to a scope. It's also impossible to create a new object and return it via Rust reference, because Rust reference doesn't mean "here, have it via pointer", but means "it's stored over there, you can have a look", which is not true for new object you're trying to return and haven't stored anywhere permanently.

Rust's type for returning by reference is Box (e.g. Box<Point>), but for a tiny object like Point the cost of a heap allocation required to get a non-temporary pointer you can return is very high relatively to just copying the Point itself.

Finally, for a trivial operation like neg, your function will get inlined. Whether you take or return a reference or not doesn't matter to LLVM — it will obliterate all such details and do it however it thinks is faster anyway.

2 Likes

Thanks for the quick replies! I really appreciate all your responses as a beginner.

@scottmcm I tried to reproduce and isolate the error on Rust playground but found myself unsuccessful - maybe I made it too complicated: Rust Playground

  • I'm trying to emulate the same test setup so it might seem weird
  • I had to leave links to my actual code in the comments as I can't post multiple links yet

@kornel thanks for the detailed response! I mostly work in weakly typed languages so I'm still trying to wrap my head around some of the concepts you mentioned but I'll definitely read over the Rust book again

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.