tl;dr in Rust, is there a "strong" type alias (or typing mechanism) such that the rustc
compiler will reject (emit an error) for mix-ups that may be the same underlying type?
Currently, type aliases of the same underlying type may be defined
type WidgetCounter = usize;
type FoobarTally = usize;
However, the compiler will not reject (emit an error or a warning) if I mistakenly mix up instances of the two type aliases.
fn tally_the_foos(tally: FoobarTally) -> FoobarTally {
// ...
tally
}
fn main() {
let wc: WidgetCounter = 33;
let ft: FoobarTally = 1;
// whoops, passed the wrong variable!
let tally_total = tally_the_foos(wc);
}
(Rust Playground)
I'm hoping for something like an additional keyword strong
strong type WidgetCounter = usize;
strong type FoobarTally = usize;
such that the previous code, when compiled, would cause a compiler error:
error[E4444]: mismatched strong alias type WidgetCounter,
expected a FoobarTally
Or maybe there is a clever trick with struct
s that would achieve this?
Or a cargo module that defines a macro to accomplish this?
I know I could "hack" this by type aliasing different number types, i.e. i32
, then u32
, then i64
, etc. But that's an ugly hack for many reasons.
Is there a way to have the compiler help me avoid these custom type alias mixups?
Rust has a nice trick called the New Type Idiom just for this. By wrapping a single item in a tuple struct, you can create a "strong" or "distinct" type wrapper.
This idiom is also mentioned briefly in the tuple struct section of the Rust docs.
The "New Type Idiom" link has a great example. Here is one similar to the types you are looking for:
// Defines two distinct types. Counter and Tally are incompatible with
// each other, even though they contain the same item type.
struct Counter(usize);
struct Tally(usize);
// You can destructure the parameter here to easily get the contained value.
fn print_tally(Tally(value): &Tally) {
println!("Tally is {}", value);
}
fn return_tally(tally: Tally) -> Tally {
tally
}
fn print_value(value: usize) {
println!("Value is {}", value);
}
fn main() {
let count: Counter = Counter(12);
let mut tally: Tally = Tally(10);
print_tally(&tally);
tally = return_tally(tally);
// This is a compile time error.
// Counter is not compatible with type Tally.
// print_tally(&count);
// The contained value can be obtained through destructuring
// or by potision.
let Tally(tally_value ) = tally;
let tally_value_from_position: usize = tally.0;
print_value(tally_value);
print_value(tally_value_from_position);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With