diff --git a/src/SUMMARY.md b/src/SUMMARY.md index cdea982..6ee99d0 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -28,3 +28,4 @@ - [Extending the capabilities of compiler-generated function types](./design_notes/fn_type_trait_impls.md) - [Auto traits](./design_notes/auto_traits.md) - [Eager drop](./design_notes/eager_drop.md) + - [Autoderef and autoref in operators](./design_notes/autoref_ops.md) diff --git a/src/design_notes/autoref_ops.md b/src/design_notes/autoref_ops.md new file mode 100644 index 0000000..c90abc5 --- /dev/null +++ b/src/design_notes/autoref_ops.md @@ -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 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. + +## History + +The standard library initially had just the basic impls of the operator traits +(e.g., `impl Add 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.