Thanks to the great work of contributors, the implementation of const generics in Rust is getting further and further along.
As such, I myself have been experimenting on nightly, and considering some future extensions. One of the things I believe might be a future UX improvement with const generics, is a way to safely "refine" a generic const generic type to a specific type, as can be done today using an unsafe transmute:
#![feature(const_generics)]
struct S<const B: bool>;
impl S<true> {
fn print_true(&self) { println!("true"); }
}
impl S<false> {
fn print_false(&self) { println!("false"); }
}
impl<const B: bool> S<{B}> {
fn print(&self) {
match B {
true => unsafe { core::mem::transmute::<&S<{B}>, &S<{true}>>(self).print_true() },
false => unsafe { core::mem::transmute::<&S<{B}>, &S<{false}>>(self).print_false() }
}
}
}
I believe this to be sound (is it?).
Note that in this trivial example the implementation of print
could be reduced to just
match B {
true => println!("true"),
false => println!("false")
}
but as a more complicated example, consider some trait implemented for specific type variant(s) but not the generic type:
trait T { fn print(&self); }
impl T for S<{true}> { ... }
impl<const B: bool> S<{B}> {
fn print(&self) {
match B {
true => <S<{true}> as T>::print(self), // error: mismatched types; expected `&S<{true}>`, found `&S<{B}>`
// or
true => <S<{B}> as T>::print(self), // error: T is not implemented for S<{B}>, found implementation for S<{true}>
false => ...
}
}
}
I believe this conditionally "refining" a generic type S<{B}>
to a specific variant S<{true}>
is
- sound, when
B == true
- potentially safe, I believe the compiler could have enough information to eliminate the need for unsafe transmutes
- useful, it allows you to use the traits, types and methods associated with a specific variant type when using the generic type, as shown in the example
Thoughts?
(I could not find if something like this has been discussed before, although the idea of bridging the gap between generic types and specific types seems similar to an earlier discussion, Exhaustiveness checks for const generic impls: if a trait is implemented for S<{true}>
and S<{false}>
, should it automatically also be implemented for S<{B}>
?)