-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Binary operator traits with specializable generic implementations #2578
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
base: master
Are you sure you want to change the base?
Conversation
Added more explanation, details, and motivational impetus for the default blanket implementation rule.
@withoutboats The compiler will need to be changed to consider the new traits, with a kink in the algorithm. Are you sure T-lang does not apply? |
Link to the specialization RFC.
Edited text to improve readablity. Added a `?Sized` bound in an example.
In binary-ops-specialization, the example does not need to provide a special case for string slices on the right hand side.
The default body of method ne2 called an eq method that's not present in this trait. The second-gen method is named eq2.
An alternative idea occurred to me: add the new style op traits not as a next-gen replacement for the Rust 1.0 traits, but as fallback generic implementations: the generic impl of WDYT? |
I don't see how this proposal solves the problem with specialization because this looks just like specialization. But only for the specified operator traits and with some new added complexity. Please elaborate on how this improves this situation. If the only difference is that it isn't a breaking change to add a Yes it is unfortunate that we can't extend |
@KrishnaSannasi For a real-world example that perhaps illustrates the problem better than the dry motivational prose of my RFC, please take a look at this long list of As suggested in my previous comment, I now think the new traits should augment the existing fully specialized operator traits rather than soft-deprecating them. The impl resolution rule does not need to be that complex, either. I will update the RFC with this idea. |
Reinvented the specializable operator overload traits as fallbacks augmenting the extant operator traits rather than replacing them.
all crates in the dependency graph to be compatible with the feature. | ||
The proposed [rule][default-implementation-rule] of defining generic | ||
operator impls slashes the quadratic explosion of mostly tedious | ||
non-generic operator trait implementations that takes place today. |
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.
Most of this tedium could be resolved through disciplined use of macros.
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.
I'm doing this, and it's still tedious 😄
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.
The macros also don't help when there is another clever container crate whose types compare to the same basic types as yours. You'd have to add a dependency on the crate, just for the impls. The authors of that crate might want to do the same for your crate, and now you have to mutually agree over what depends on what and under which feature flags.
The generic impl does it automagically and with no extra dependencies, as long as there is a fitting Borrow
.
considered together with its operand type family for the following rule. | ||
Types in each such family usually implement `Borrow` to the base operand type, | ||
and their binary operator trait impls, as currently provided, tend to cover | ||
any possible pairs with the other types in the family. |
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.
Why not just impl PartialEq
and such for just the base varaints? Then force people to convert the owned versions to do the comparison? Is that too much of an ergonomic hit?
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.
Yes, using .as_str()
and .as_bytes()
everywhere for a workalike type with a different ownership model is incredibly annoying and inelegant. Especially considering that we have other generic APIs using Borrow
where all lender types for the same target work interchangeably.
for non-`Copy` types: these should not work between two borrowed | ||
values to avoid allocations or other side effects hidden in operator notation, | ||
while moving both owned operands into an operator expression | ||
may be non-ergonomic. | ||
A precedent is set in the `Add` implementation for `String` to only let |
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.
More than a few are unhappy with this precedent, and would like to see it changed.
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.
I see no really good alternatives that could have been chosen with the non-specializable Add
for Rust 1.0. There are probably other considerations for some owned types without open-ended Borrow
/Deref
kinship. What do linear algebra people do?
Provide new fallback traits for overloading binary operators, such as
DefaultPartialEq
,DefaultPartialOrd
,DefaultAdd
,DefaultAddAssign
, etc., with default blanket implementations abstracted overBorrow
for built-in and standard library types. This will drastically reduce the number of explicit impl items necessary to cover operator-compatible type pairs. When resolving the implementation for an operator, the compiler will consider the new traits as the second choice after the plain old non-specializable overload traits.Edited: previous revisions proposed next-gen operator overload traits to replace the Rust 1.0 traits, with a complicated overload resolution rule for backward compatibility.
Rendered view