Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Operator overloading by value results in use of moved value

Compiling the following Rust code that uses operator overloading

use std::ops::{Add};

#[derive(Show)]
struct Point {
    x: int,
    y: int
}

impl Add for Point {
    type Output = Point;

    fn add(self, other: Point) -> Point {
        Point {x: self.x + other.x, y: self.y + other.y}
    }
}

fn main() {
    let p: Point = Point {x: 1, y: 0};
    let pp = p + p;
}

Results in compiler errors due to ownership of p:

<anon>:21:18: 21:19 error: use of moved value: `p`
<anon>:21     let pp = p + p;
                           ^
<anon>:21:14: 21:15 note: `p` moved here because it has type `Point`, which is non-copyable
<anon>:21     let pp = p + p;
                       ^

The rationale behind it is explained here and led to an RFC that was not accepted (part of due to reasons of the above example). However, later the following RFC still introduced the by-value type signatures for operators.

While I understand the rationale behind the decision. Due to my lack of experience in rust, I'm not sure what the "proper" way would be to allow the above code to work (a) if I do not want to copy or (b) how to make the struct copyable?

like image 290
zgerd Avatar asked Jan 09 '15 09:01

zgerd


People also ask

What should an overloaded operator return?

Operator Overloading is the method by which we can change the function of some specific operators to do some different task. In the above syntax Return_Type is value type to be returned to another object, operator op is the function where the operator is a keyword and op is the operator to be overloaded.

Which of the following operator is by default overloaded by the compiler?

Which of the following operators are overloaded by default by the compiler in every user defined classes even if user has not written? Explanation: Assign operator is by default available in all user defined classes even if user has not implemented.

How does a Python class handle operator overloading?

The operator overloading in Python means provide extended meaning beyond their predefined operational meaning. Such as, we use the "+" operator for adding two integers as well as joining two strings or merging two lists. We can achieve this as the "+" operator is overloaded by the "int" class and "str" class.


1 Answers

If you don't want to copy then, as far as my newbie understanding goes, you need to implement Add on references to Point.

This would be supported by the RFC:

Fortunately, there is no loss in expressiveness, since you can always implement the trait on reference types. However, for types that do need to be taken by reference, there is a slight loss in ergonomics since you may need to explicitly borrow the operands with &. The upside is that the ownership semantics become clearer: they more closely resemble normal function arguments.

And indeed it seems to work:

use std::ops::{Add};

#[derive(Show)]
struct Point {
    x: i32,
    y: i32
}

impl<'a> Add for &'a Point {
    type Output = Point;

    fn add(self, other: &'a Point) -> Point { //'
        Point {x: self.x + other.x, y: self.y + other.y}
    }
}

fn main() {
    let p: Point = Point {x: 1, y: 0};
    let pp = &p + &p;
    println!("{:?}", pp);
}

(playpen)

To make Point copyable instead, just replace #[derive(Show)] with #[derive(Show,Copy)]. Such structs used to be copyable by default, but it changed.

like image 121
Michał Politowski Avatar answered Oct 01 '22 00:10

Michał Politowski