Because uninitialized
and zeroed
are not only ways to create uninhabited type values, e.g. you can write:
let a: Void = unsafe { mem::transmute(ZstType) };
And I think there is other holes like that, which I can’t recall now. So shouldn’t we simply place Inhabited
trait bounds on function and let type system handle it from here? And in some cases you may want to use !Inhabitted
trait bound, as in marker types, or if we’ll take Result
:
// Inhabited bound is redundant, I'll use it for explicitness
impl<T: Inhabited, E: !Inhabited> Result<T, E> {
/// Safely unwraps Ok variant
fn always_ok(self) -> T {
// I think it will not work today, but in future compiler may
// prove that Result<T, !> is equivalent to T
unsafe { mem::transmute(self) }
}
}
impl<T: !Inhabited, E: Inhabited> Result<T, E> {
fn always_err(self) -> E { .. }
}
One of the arguments which I’ve heard against Inhabited
trait bound is that it will make things like Box<[!]>
to require explicit ?Inhabited
bounds, which can infect a lot of code bases. But I haven’t heard an explanation why we need such strange types in the first place.