Rationale
Why overflow has three spellings
A health bar saturates, a hash wraps, and a count should fail.
Why does overflow have three spellings?
Because there are three right answers and which one is right is a fact about the program rather than about the type. A health bar saturates, a hash wraps, and a count should fail, and a language with one behaviour is wrong for two of those every time.
The default is the loud one
A plain + fails rather than producing a value outside the type, so the case you did not think about surfaces rather than becoming a small wrong number. The two quiet behaviours have to be asked for by name.
// Integers say what they do when a result does not fit. There is no undefined behaviour.
//
// A plain `+` fails rather than producing a value outside the type. `+%` wraps and `+|` saturates,
// and choosing is the point: a health bar saturates, a hash wraps, a count should fail.
fn health(current: u8, healed: u8) -> u8 {
return current +| healed
}
fn hashStep(accumulator: u32, value: u32) -> u32 {
return accumulator *% value
}
// Units are erased. `30m` is the number 30; `250ms` is 0.25, because seconds are the base unit.
fn reach() -> f32 {
return 30m
}
fn beat() -> f32 {
return 250ms
}
Why the spellings are refused on floats
`a +% b` on an f32 is an error rather than a synonym for +. Floats neither wrap nor saturate, and accepting the spelling would teach that the distinction is decorative, which is the one thing this design cannot afford a reader to conclude.
And refused on the widest integers, for a different reason
Floats are refused the spelling because they have no wrapping behaviour to name. i64 and u64 are refused it because this backend cannot compute one: wrapping needs the true result before it is reduced, and two values near the top of those types add past the range a double holds exactly. Naming the refusal beats producing something wrapping-shaped and slightly off, which is the instinct the plain + follows as well.
What it costs
Three operators to learn where most languages have one, and a decision at every integer addition. In arithmetic that genuinely cannot overflow, that decision is pure overhead, and the language offers no way to say so once and be done.