aha, I see that now. Thanks for the clarification consider this a friendly bump for the topic then
Yeah, the current recommendation is to either use wrapping_xxx
methods or the Wrapping<T>
types, whichever is more convenient.
I am curious to find out why all of your code would need to switch to Wrapping
. I'd have thought that you'd only need to deal with Wrapping
at the interface boundary?
FWIW, one of the major pain-points with Wrapping<T>
is that heterogeneous operations - e.g. T + Wrapping<T>
- are not permitted. This is because itās not obvious whether such an operation should wrap or not. In different words, one of the operands essentially needs to be casted before performing the operation, and itās not clear which one.
Iām now kind of leaning towards saying that Wrapping<T>
should āwinā: in other words, that we should have impl Add<u32> for Wrapping<u32> { type Output = Wrapping<u32>; ... }
(and vice versa), and likewise for the other types. The intuition is this: the reason why āplainā T
(e.g. u32
) panics on over/underflow is not because this is well-known to be the behavior thatās desired by users of u32
; rather, the reason is precisely that we donāt have any information about the programmerās intent, so our only reasonable option is to signal the unhandled circumstance by panicking. (This is also underscored by the fact that panicking only happens in debug builds: if we knew that panicking is what the programmer explicitly wants, then we would do it always.)
Now in the case of u32 + Wrapping<u32>
, if we think of it as a unification problem, then āno available informationā unifies with āit should wrapā to yield āit should wrapā.
(Incidentally, for completenessās sake, we should presumably also have Saturating<T>
, Checked<T>
, and Overflowing<T>
for the other possible policies, with analogous impl
s. And see also.)
I disagree. This would amount to making one Wrapping value āinfectā all surrounding operations with non-wrapping values; and sometimes wrapping can lead to counter-intuitive results. Therefore if we allow it, the Output
type should be u32
. One can always add another Wrapping(ā¦) around it to ensure the result wraps.
Hmm. The idea was actually to protect against accidents by giving a type error if u32
was expected but a Wrapping<u32>
resulted (i.e., the scenario where I wrote T + Wrapping<T>
but didnāt actually want it to wrap). Iām not sure how that squares with the āunification of informationā idea, actually. I can see how it might backfire when the result type is inferred instead of checked.
One place where there arenāt questions around the choice of result type, though, is AddAssign
(+=
) and family. I think it would be completely, unambiguously fine to have impl AddAssign<u32> for Wrapping<u32>
as a wrapping operation. (Right now it seems we donāt even have AddAssign<Wrapping<u32>> for Wrapping<u32>
!)
I worry that this could get rather confusing for more complicated expressions. For example, even just u32 + u32 + Wrapping<u32>
would yield a Wrapping<u32>
, but could still panic if the first addition overflowed. Maybe thatās what is desired, but it seems more likely that it isnāt.
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.