[rust-dev] Fwd: &self/&mut self in traits considered harmful(?)

Tommi rusty.gates at icloud.com
Tue Jun 17 02:48:49 PDT 2014


Here's one use case your proposal doesn't cover:
Subtracting two points returns a vector, which either has the same internal representation as a point or uses point as its internal representation, and thus, despite the return type of the subtraction operation being different from `Self`, it's still eligible for the implicit move-optimization.

For example, assuming a `Sub` definition that moves `self`:

struct Point {
    coordinates: Vec<int>
}

struct Vector {
    end_point: Point
}

impl Sub<Point, Vector> for Point {
    fn sub(self, rhs: &Point) -> Vector {
        for (left, right) in self.coordinates.mut_iter().zip(rhs.coordinates.iter()) {
            *left -= *right;
        }
        Vector { end_point: self }
    }
}

On 2014-06-17, at 11:04, Jan Klesnil <klesnil at centrum.cz> wrote:

> Hi,
> 
> Maybe we should look at the problem from other perspective? Currently the x += y expression is sugar for x = x + y. Can we flip it over and make x = x + y expression sugar for x = { let tmp = x; tmp += y }? What to do for non-Copy types then?
> 
> It can be fixed by having traits for both + and += operators with default implementation of Add for Copy types.
> 
> trait Add<RHS> {
>  fn add(&mut self, &rhs : RHS);
> }
> 
> trait BinaryAdd<RHS, RES> {
>  fn add(&self, &rhs : RHS) -> RES;
> }
> 
> impl<RHS, T : Copy + Add<RHS>> BinaryAdd<RHS, T> for T {
>  fn add(&self, &rhs : RHS) -> T {
>    let mut tmp = self;
>    tmp += rhs;
>    tmp
>  }
> }
> 
> For any addable type you either implement Add and Copy, or Add and BinaryAdd if the type is too expensive to be implicitly copyable, or just the BinaryAdd if the result's type is different from Self.
> 
> Then the rustc may be allowed to use Add instead of BinaryAdd for temporary values and for += expressions:
> let a = a + b;  => a += b;
> let c = get_new_foo() + b;  => let c=get_new_foo(); c+=b;
> c += a;
> 
> It will be user's responsibility to provide compatible implementations for Add and BinaryAdd (results, side-effects, etc.).
> 
> JK
> 
> On 16.6.2014 16:32, Sebastian Gesemann wrote:
>> The following message got sent to Patrick instead to the list by mistake.
>> Sorry, Patrick!
>> 
>> ---------- Forwarded message ----------
>> From: s.gesemann at gmail.com
>> Date: Mon, Jun 16, 2014 at 4:29 PM
>> Subject: Re: [rust-dev] &self/&mut self in traits considered harmful(?)
>> To: Patrick Walton <pcwalton at mozilla.com>
>> 
>> 
>> On Sat, Jun 14, 2014 at 2:46 AM, Patrick Walton wrote:
>>> I have filed RFC #118 for this:
>>> https://github.com/rust-lang/rfcs/pull/118
>>> 
>>> Patrick
>> Bold move. But I'm not convinced that this is a good idea. I may be
>> missing something, but forcing a move as opposed to forcing an
>> immutable reference seems just as bad as an approach. Also, I'm not
>> sure why you mention C++ rvalue references there. References in C++
>> are not objects/values like C++ Pointers or References in Rust. They
>> are auto-borrowing and auto-deref'ing non-values, so to speak. These
>> different kinds of L- and Rvalue references combined with overloading
>> is what makes C++ enable move semantics.
>> 
>> I think one aspect of the issue is Rust's Trait system itself. It
>> tries to kill two birds with one stone: (1) Having "Interfaces" with
>> runtime dispatching where Traits are used as dynamically-sized types
>> and (2) as type bound for generics. Initially, I found this to be a
>> very cool Rust feature. But now, I'm not so sure about that anymore.
>> Back in 2009 when "concepts" were considered for C++ standardization,
>> I spent much time on understanding the intricacies of that C++ topic.
>> This initial "concepts" design also tried to define some type
>> requirements in terms of function signatures. But this actually
>> interacted somewhat badly with rvalue references (among other things)
>> and I think this is one of the reasons why "concepts lite" (a new and
>> simplified incarnation of the concepts design, expected to augment
>> C++1y standard in form of a technical report) replaced the function
>> signatures with "usage patterns". As a user of some well-behaved type,
>> I don't really care about what kind of optimizations it offers for +
>> or * and how they work. I'm just glad that I can "use" the "pattern"
>> x*y where x and y refer to instances of some type. Whether the
>> implementer of that type distinguishes between lvalues and rvalues via
>> overloading or not is kind of an implementation detail that does not
>> affect how the type is being used syntactically. So, I expect "C++
>> concepts lite" to be able to specify type requirements in terms of
>> "usage patters" in a way that it allows "models" of these "concepts"
>> to satisfy the requirements in a number of ways (with move
>> optimizations being optional but possible).
>> 
>> Another thing I'm not 100% comfortable with (yet?) is the funky way
>> references are used in Rust in combination with auto-borrowing (for
>> operators and self at least) and auto-deref'ing while at the same
>> time, they are used as "values" (like C++ pointers as opposed to C++
>> references). I've trouble putting this into words. But it feels to me
>> like the lines are blurred which could cause some trouble or bad
>> surprizes.
>> 
>> Assuming this RFC is accepted: How would I have to implement Add for a
>> custom type T where moving doesn't make much sense and I'd rather use
>> immutable references to bind the operands? I could write
>> 
>>    impl Add<&T,T> for &T {...}
>> 
>> but it seems to me that this requires explicit borrowing in the user code à la
>> 
>>    let x: T = ...;
>>    let y: T = ...;
>>    let c = &x + &y;
>> 
>> Or is this also handled via implicit borrowing for operators (making
>> operators a special case)?
>> 
>> Still, I find it very weird to impl Add for &T instead of T and have
>> this asymmetry between &T and T for operands and return value.
>> 
>> Can you shed some more light on your RFC? Maybe including examples? A
>> discussion about the implications? How it would affect Trait-lookup,
>> implicit borrowing etc? What did you mean by "The AutorefArgs stuff in
>> typeck will be removed; all overloaded operators will typecheck as
>> though they were DontAutorefArgs."? Many thanks in advance!
>> 
>> Cheers
>> sg
>> _______________________________________________
>> Rust-dev mailing list
>> Rust-dev at mozilla.org
>> https://mail.mozilla.org/listinfo/rust-dev
> 
> _______________________________________________
> Rust-dev mailing list
> Rust-dev at mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev



More information about the Rust-dev mailing list