-
Notifications
You must be signed in to change notification settings - Fork 1.6k
RFC: Overloaded arithmetic and logical operators should take self
and their arguments by value
#118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
their arguments by value.
|
||
# Drawbacks | ||
|
||
Some use cases of `+`, such as string and array concatentation, may become more verbose. It is likely that many of the use cases of `+` today will be compatible with these new semantics. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fortunately we do neither of those with the +
operator.
This wouldn't work:
...and if you change the signature to:
...then the function creates an unnecessary clone if the type of |
@tommit I believe your usecase would be more efficiently addressed by supporting |
I think the solution to this issue should also cover any user-defined mathematical operators and other user-defined functions, like a trait for types that implement cross product. |
It seems that this would stop types like |
This would alter the plans for augmented assignment significantly; the distinct traits would be rendered unnecessary. As it is, the augmented assignment traits were still going to be taking the LHS by reference rather than by value. I can see how this decreases complexity in some areas, especially as by-value LHS was going to be needed for augmented assignment at least and so it was going to be two traits to implement rather than one. Still, I am not at all comfortable with this change; I certainly won’t go claiming it to be a Bad Thing™ as I simply don’t know that, but it will certainly lead to some surprises, e.g. that I agree that the functionality offered here is a superset of that offered with references (though presumably sans-autoref and thus uglier), but I question how much people will actually go implementing things for all the feasible combinations of things. I believe that the RHS will normally only need—or want, for that matter—a reference. Are we going to have people writing four ( Yes, there are certainly concrete benefits from doing this. But there are also non-trivial risks (I won’t judge how great they are—at present I’m more interested in raising questions than answering them!) and it is a significant break from the traditions of all languages that I know (C++ is notably excluded from that set; I do not have any firm grasp on its operator overloading), one which is certain to lead to confusion in some people. |
Function overloading would solve a lot (all?) of the downsides of this approach. The compiler could choose the right overload. This is why move constructors work well in C++; they're picked over the copy constructor by the compiler because of the rvalue reference parameter (while the copy ctor has a plain const ref). I'm not saying Rust needs move/copy ctors, but I am saying function overloading would solve problems here and elsewhere in Rust. |
That's not overloading. That's ad-hoc templating. In general I am quite opposed to ad-hoc templates; I think strongly-typed generics are superior in pretty much all respects. |
@pcwalton I think you misunderstood what I was trying to say (I probably wasn't clear enough). I was trying to say we could have overloads for say pub trait Add<RHS,Result> {
fn add(self, rhs: RHS) -> Result;
fn add(&self, rhs: RHS) -> Result;
} You get the idea. The compiler could then pick the most appropriate one. I am most certainly not advocating ad-hoc templating à la C++. We agree they are a terrible experience. Strongly-typed generics are a Rust selling point (other C++ devs drool when I mention them). |
@Valloric That's no different semantically or compiler-implementation-wise from simply implementing the proposed |
@Kimundi yeah, but that's not really important. The type of the receiver is the same in both cases ( |
So, if I
|
IMHO, this RFC needs a more thorough analysis w.r.t. its implications. So far, I'm not convinced that the benefits outweigh the costs. Certain situations are improved (e.g. when values are only consumed once). In other situations the performance will be worse (e.g. If values are used more than once this requires explicit clone() to avoid "already moved"-errors. However, if the operator's implementation is not able to reuse the clones' buffers for the result but requires an out-of-place computation (only reading the arguments and computing the value in a new buffer), these clones would have been unnecessary! Think about BigInt multiplication here) And finally, it will make some expressions involving expensive types uglier due to clone(). I would also like to stress that the idea to impl these Traits for references &T instead of T à la Add<&T,T> for &T is a bad idea because it does not compose well with generic functions<T: Add<T,T>> since T would not be Add<T,T> in that case. |
@sellibitze This is a good point. If it doesn't help BigInt, then there isn't much of a point in doing it. |
Once rust gets associated types, there could be a |
Doesn't this make addition/other operations more expensive? Since operands like BigInts, (algebraic) vectors, matrices, or N-dimensional arrays would have to be copied into a new stack whenever these are performed. Unless the implication is that these copies are guaranteed to be eliminated by the compiler. |
@alexchandel most of those will be behind a pointer, e.g. |
Closing because I don't like this anymore. |
RFC process improvements.
self
andself
and their arguments by value
No description provided.