Guide
Integers and overflow
Three spellings for arithmetic, and choosing between them is the point.
There is no undefined integer behaviour. Every arithmetic operator on an integer says what it does when the result does not fit, and choosing between them is the point rather than a chore.
Three spellings
A plain + fails rather than producing a value outside the type. +% wraps. +| saturates. A health bar saturates, a hash wraps, and a count should fail, so the language makes you say which one this is.
// 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
}
Wrapping needs an integer
`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.
Wrapping is refused on the widest two
Wrapping is defined on the true result before it is reduced into the type. Every narrower width can compute that result exactly first, because two u32 values add to something a double still holds. Two u64 values near the top add to almost 2^54, where doubles sit two apart and the sum is rounded before anything can reduce it. So a +% b and u64.wrap(v) are errors naming the type. Checked and saturating arithmetic work at every width, since both only have to be exact inside the range and a result outside it throws or clamps.
A literal is checked against its type
let n: u8 = 300 is refused, and so is a literal past what a u64 can hold here. The two diagnostics differ because the fixes do: one number is too large for eight bits, and the other is too large for a double to tell apart from its neighbour.
f32 rounds at every operation
That is what single precision means, and the same expression gives the same answer here as it does in a shader. It is visible in the output of any box that returns one.