In theory, in the future, when Rust supports constants as template arguments, one might even add a const argument, the value that should be used as "null". E.g. if my u8 never reaches 255, I could use something like Never<u8, 255>.
In theory, in the future, when Rust supports constants as template arguments, one might even add a const argument, the value that should be used as "null". E.g. if my u8 never reaches 255, I could use something like Never<u8, 255>.
The real motivation is
> With NonNull covering pointers, the remaining use cases for NonZero are integers.
It's unclear how extensible we truly want this to be, and so we decided to go with the concrete types. In the worst case, we'd eventually re-introduce some sort of NonZero<T>, and deprecate these types. This was deemed worth it to let people use this important feature on stable, rather than waiting and seeing if we ever decide to do otherwise.
The RFC covers this. https://github.com/rust-lang/rfcs/blob/master/text/2307-conc... Also see the RFC discussion at https://github.com/rust-lang/rfcs/pull/2307
Basically the generic NonZero already existed, but it's hard to express safely when used with arbitrary user types.
>In theory, in the future, when Rust supports constants as template arguments, one might even add a const argument, the value that should be used as "null". E.g. if my u8 never reaches 255, I could use something like Never<u8, 255>.
This requires const generics, so it could happen when they're implemented. (This is also mentioned in the RFC discussion.)
struct RectangularArray<T, const WIDTH: usize, const HEIGHT: usize> {
array: [[T; WIDTH]; HEIGHT],
}
const X: usize = 7;
fn main() {
let x: RectangularArray<i32, 2, 4>;
let y: RectangularArray<i32, X, {2 * 2}>;
}
I haven't read enough about singleton types to know the exact details about their similarities, so I'm not sure.Fully general dependent type would allow passing in runtime values, which is significantly harder to type-check and execute
enum Option<T> {
Some(T),
None,
}
Under the hood, this is a "tagged union"; Rust has to have enough space for the T, but also for a tag, to say which variant is the current one.If T is a NonZero type, then we know that zero is never a valid value. That means that instead, Rust can use the zero value to mean the None case, and any other value to be the Some case, completely eliminating the extra tag, and reducing the size of the Option.
This is a good example of a "zero-cost abstraction"; an Option in this case has absolutely no extra associated overhead at runtime.
Note that these optimizations aren't specialized for Option; they apply to anything that has this kind of shape.
I suppose you could always wrap NonZero with an accessor that adds 1 if negative to achieve the same result, though that might be too much overhead to be worth it.