-
Notifications
You must be signed in to change notification settings - Fork 51
Autoref/autoderef for operators #63
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
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Autoref/Autoderef in operators | ||
|
||
Rust permits overriding most of the operators (e.g., `+`, `-`, `+=`). In part | ||
due to `Copy` types not auto-dereferencing, it is common to have `T + &T` | ||
or `&T + &T`, with potentially many levels of indirection on either side of the | ||
operator. | ||
|
||
There is desire in general to avoid needing to both add impls for referenced | ||
versions of types because they: | ||
|
||
- bloat documentation | ||
- are never quite sufficient (always more references are possible) | ||
- can cause inference regressions, as the compiler cannot in general know that | ||
`&T + &T` is essentially equivalent at runtime to `T + T`. | ||
|
||
The inference regressions are the primary target of historical discussions. | ||
|
||
The tradeoff to some feature like this may either mean that the exact impl | ||
executed at runtime is harder to determine, or that the compiler is | ||
synthetically generating new implementations for some subset of types, | ||
potentially adding confusion around which impls are actually present. | ||
|
||
However, generic code may want the impls on references because the generic code | ||
may not want to require `T: Copy`. One version of this could involve | ||
something like `default impl<T:Copy> Add<&T> for &T` so that people don't *need* | ||
to write special impls themselves. It's worth noting that this still would need | ||
some special support in the compiler to avoid the two possible impls leading to | ||
inference regressions. | ||
|
||
Mark-Simulacrum marked this conversation as resolved.
Show resolved
Hide resolved
|
||
## History | ||
|
||
The standard library initially had just the basic impls of the operator traits | ||
(e.g., `impl Add<u64> for u64`) but has since gained `&u64 + &u64`, `u64 + &u64` | ||
and `&u64 + u64`. These impls usually cause some amount of inference breakage in | ||
practice. | ||
|
||
Especially with non-Copy types (for example bigints), forcing users to add references can be | ||
increasingly verbose: `&u * &(&(&u.square() + &(&a * &u)) + &one)`, for example. | ||
|
||
There have also been a number of discussions on RFCs and issues, including: | ||
- [Rust tracking issue #44762](https://github.com/rust-lang/rust/issues/44762) | ||
- This includes some implementation/mentoring notes. | ||
- [RFC 2147](https://github.com/rust-lang/rfcs/pull/2147) | ||
- [Trying to add T op= &T](https://github.com/rust-lang/rust/pull/41336) | ||
- Showcases dealing with inference breakage regressions when adding new | ||
reference-taking impls. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 think this note accurately captures the primary benefits of this: the compiler could avoid inference failures by considering the reference and non-reference possibilities without them being completely separate impls.
It might be worth mentioning something here about other tradeoffs. And in particular, we should consider whether there are circumstances where we might not want this behavior for a type, and whether people should be able to opt into or out of this behavior for a type.