Relevant RFC "928" (rust-lang/rfcs#928).
Public API
The Wrapping and Saturating types enforce that a certain behaviour for all operations on the underlying integer is performed - .wrapping_* or .saturating_*. When doing the "simplified" operations, .add always becomes .wrapping_add or .saturating_add, .sub always becomes .wrapping_sub / .saturating_sub and so on.
The fundamental ideas seem to be:
- Never perform the an integer operation with the wrong behaviour by forgetting to write
.wrapping_* or .saturating_*
- Reduce boiler-plate code / text by being able to omit writing
.wrapping_* or .saturating_*
But number 2 seems to fall short in reality. The traits in core::ops:: are only implemented for Wrapping and Saturating where the other type is Wrapping or Saturating as well (impl core::ops::*<Wrapping<T>> for Wrapping<T>¹). So, instead of writing a integer addition like this:
let mut value = 17u8;
// ...
value += 8;
value *= 7;
// ...
let other: u8 = value / 3;
for Wrapping and Saturating types, it looks likes this:
let mut value = Wrapping(17u8);
// ...
value += Wrapping(8);
value *= Wrapping(7);
// ...
let other: Wrapping<u8> = value / Wrapping(3);
This introduces the need for additional mentions of Wrapping / Saturating in every code location where an integer operation is performed - and in my opinion, adds unnecessary noise to the code. In my opinion, having the integer being wrapped in either Wrapping or Saturating in the declaration / initialization should be all that is needed.
I propose that - in addition to impl core::ops::*<Wrapping<T>> for Wrapping<T>¹ - the integer operations are also implemented using the raw integer type itself (impl core::ops::*<T> for Wrapping<T>¹), and therefore the following is being made possible:
let mut value = Wrapping(17u8);
// ...
value += 8;
value *= 7;
// ...
let other: Wrapping<u8> = value / 3;
¹ as well as for Saturating
Steps / History
Unresolved Questions
Relevant RFC "928" (rust-lang/rfcs#928).
Saturatingtype #87920Public API
The
WrappingandSaturatingtypes enforce that a certain behaviour for all operations on the underlying integer is performed -.wrapping_*or.saturating_*. When doing the "simplified" operations,.addalways becomes.wrapping_addor.saturating_add,.subalways becomes.wrapping_sub/.saturating_suband so on.The fundamental ideas seem to be:
.wrapping_*or.saturating_*.wrapping_*or.saturating_*But number 2 seems to fall short in reality. The traits in
core::ops::are only implemented forWrappingandSaturatingwhere the other type isWrappingorSaturatingas well (impl core::ops::*<Wrapping<T>> for Wrapping<T>¹). So, instead of writing a integer addition like this:for
WrappingandSaturatingtypes, it looks likes this:This introduces the need for additional mentions of
Wrapping/Saturatingin every code location where an integer operation is performed - and in my opinion, adds unnecessary noise to the code. In my opinion, having the integer being wrapped in eitherWrappingorSaturatingin the declaration / initialization should be all that is needed.I propose that - in addition to
impl core::ops::*<Wrapping<T>> for Wrapping<T>¹ - the integer operations are also implemented using the raw integer type itself (impl core::ops::*<T> for Wrapping<T>¹), and therefore the following is being made possible:¹ as well as for
SaturatingSteps / History
Wrappingtype Tracking issue for integer methods for Wrapping #32463Saturatingtype Tracking Issue forSaturatingtype #87920WrappingTBDSaturatingTracking Issue forsaturating_int_assign_impl#92354WrappingSaturatingUnresolved Questions
Following "The overarching philosophy is: do whatever is easiest", I created this PR because the underlying types already exist, and it "only" proposes additional trait impls. Or does this change need a proper RFC?