The code you are looking for to increment x
is most likely
let incremented = x.checked_add(1.into()).ok_or(MyError)?;
The primary reason that Saturating
and Checked{Add/Div/Mul}
traits are used in Substrate is that overflowing/underflowing in runtime code is really bad. Rust panics on overflow/underflow in debug mode, but will silently wrap arithmetic in release mode, as specified by RFC 560.
For saturating arithmetic, you are correct that there are not too many typical use cases for this behavior, and most of the time you do want the erroring variant (which is the CheckedAdd
mentioned above). Although saturating instead of wrapping is typically less damaging, they both violate the consistency of your state, and preventing saturation and wrapping is much better. The Checked{x}
traits provide signatures that return None
on over/underflow, at which point you can error. Most of the time, this is what you want.
// From CheckedAdd
fn checked_add(&self, v: &Self) -> Option<Self>
Saturating arithmetic should only be used when you would otherwise need to include a check for overflow/underflow, and set it to the corresponding extreme value. The use cases below should make this clear.
Saturating
Use Cases
This is copied from a good post on the rust forums:
Make the player lose 10 coins when they die, avoiding overflow:
player.coins = player.coins.saturating_sub(10);
Align some text to the middle, but if it is too large align it to the left edge:
let position = (total_width/2).saturating_sub(text_width/2);
Parse a digit into a number n, capping off too large numbers such that "8354" will be cut off at 255:
n = n.saturating_mul(10_u8).saturating_add(digit);
Move the cursor to the left unless it is at the left edge:
cursor.position.x = cursor.position.x.saturating_sub(1);