Operator Overloading
afck opened this issue · comments
Would it make sense to overload the arithmetic operators (std::ops
) for everything that has an add
, add_assign
, mul
or mul_assign
method? I would love being able to write x += y;
instead of x.add_assign(y)
, but I know that there are arguments against it, too. It certainly would make some heavy computation "feel" more lightweight than it is.
What's your opinion on this? If you are fine with it, I'd be happy to try and make e.g. Field: AddAssign + MulAssign + SubAssign + Neg
, and CurveAffine: Mul + Neg
.
I would have loved to do that at the time. I don't think Rust had AddAssign
when I first wrote this implementation as part of another library, and the alternative overloading was impossible to express as a supertrait.
I would definitely love to see the impact of that and would be happy to merge it, though I would rather not import MulAssign
at callsites and rather just have all code that invokes add_assign,sub_assign,mul_assign throughout the library switch to use the operator overloading instead.
Great, I'll give it a try, probably some time next week.
Thank you for the warnings, @burdges! 😄
My plan for now is just to only add the operators whose implementations are already there: If there's an add_assign(&mut self, Self)
, use it in AddAssign<RHS = Self>
etc. I wouldn't try to add lots of variants for different combinations of references right away, or hide multiple operations (e.g. clone
and add_assign
) behind an innocent-looking symbol ("+
").
Those kinds of ergonomics improvements should probably be added separately and discussed case-by-case.
I made a start with AddAssign
: afck@15169b6
It makes Field
require for<'r> ops::AddAssign<&'r Self>
and removes the trait's own (conflicting) add_assign
method.
Could you please have a look whether you'd be okay with that kind of implementation? Then I'll do the same for MulAssign
, SubAssign
, ShrAssign
and ShlAssign
, where appropriate. (I'm not sure whether it will be feasible for e.g. Mul
.)
One good test is to see how it impacts downstream libraries and benchmarks. I'll do this when I get a chance.
I am very busy but I submitted a partial review.
One good test is to see how it impacts downstream libraries and benchmarks.
Unfortunately it will be backwards-incompatible, since the existing method add_assign
conflicts with the trait's method. (A quick fix for dependent crates is to just import the AddAssign
trait; no need to replace all calls with operators.)
I'm hoping that performance shouldn't change: The implementations are identical and I carried over all the #[inline]
attributes.
I am very busy but I submitted a partial review.
I can't see any comments (and didn't open a PR for this).
I can't see any comments (and didn't open a PR for this).
Yeah, I don't know where my review was or what I was even referring to!