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: [email protected]
Date: Mon, Jun 16, 2014 at 4:29 PM
Subject: Re: [rust-dev] &self/&mut self in traits considered harmful(?)
To: Patrick Walton <[email protected]>
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
[email protected]
https://mail.mozilla.org/listinfo/rust-dev
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev