Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is a returned value moved or not?

Tags:

rust

With this code:

struct Point {
    x: f64,
    y: f64,
}

struct Rectangle {
    p1: Point,
    p2: Point,
}

impl Rectangle {
    pub fn new(x1: f64, y1: f64, x2: f64, y2: f64) -> Rectangle {
        let r = Rectangle {
            p1: Point { x: x1, y: y1 },
            p2: Point { x: x2, y: y2 },
        };
        // some code where r is used
        r
    }
}

let rectangle = Rectangle::new(0.0, 0.0, 10.0, 10.0);

From a memory point of view, is rectangle the same instance as r, or is it a copy of r?

Do I have to explicitly return by reference (something like &r)?

I have to create millions of rectangles, and I don't want there to be useless copies.

like image 966
barbacan Avatar asked Dec 03 '22 21:12

barbacan


1 Answers

From a memory point of view, is rectangle the same instance as r, or is it a copy of r?

Unspecified.

The Rust language specifies the semantics of the language, and while they do constrain the implementation somewhat, in this case they do not. How a return value is passed up the call stack is part of the ABI, and not only is the ABI unstable (in Rust), it's also platform specific.

Do I have to explicitly return by reference (something like &r)?

Returning by reference is not possible.

You could return a Box<Rectangle> but the cost of the memory allocation would dwarf the cost of copying a Rectangle in the first place, so it's hardly advisable.

You could force this using output parameters instead, but this has other issues:

  • if you have a &mut Rectangle parameter, you first need to have a valid instance, which has to be initialized; rather wasteful,
  • if you have a *mut Rectangle pointing to uninitialized memory, you need to use unsafe code, hardly satisfying.

However...

I have to create millions of rectangles, and I don't want there to be useless copies.

I think you are worrying for nothing.

The first rule of performance tuning is measure first; and I doubt that you'll be able to observe a performance issue in the creation of those millions of rectangles.

The compiler has multiple tricks up its sleeves, such as:

  • not even materializing the rectangle instance to start with, but pass its components via CPU registers instead,
  • inlining new at the call site, avoiding any copy whatsoever,
  • ...

Thus, before worrying about the cost of copying 4 f64, I would implement the naive solution, compile in release mode, and observe what happens.

like image 131
Matthieu M. Avatar answered Jan 04 '23 14:01

Matthieu M.