An uninhabited type is a type which cannot have a representation at runtime no matter what you do, and enforces this is in a structural manner.
I'm going to use Rust as an example, because it does have uninhabited types. Rust has enums, for example:
enum Color {
Red,
Yellow,
Rgb(u8, u8, u8),
}
And you can specify a color, e.g. Color::Red
or Color::Rgb(255, 255, 255)
.
But what if you declare an empty enum:
enum Never {}
How would you construct a value of this enum? What goes after Never::
?
The answer is "it cannot be done". There is no possible representation of Never
in the language. This makes the type uninhabited.
What does "in a structural manner" mean? Another way to put it is "even disregarding encapsulation boundaries". A lot of code is written to uphold certain invariants outside of an encapsulation boundary.
For example, consider a file where the only contents are:
pub struct MyType(());
This type has no attached constructors, and the module doesn't have any functions that return MyType
. In other words, MyType
can be named as a type but cannot be constructed.
However, MyType
can be represented at runtime, just not created at runtime. In other words, the lack of constructability of MyType
is enforced via encapsulation boundaries rather than it being a property of the structure of MyType
itself. This means that MyType
is not uninhabited. But it might be the best you can do in many languages.
This is related to why enums are called "sum types" and structs are called "product types" -- the identity element of the sum operation is zero, and the identity element of the product operation is one.
void
is an uninhabited type. $\endgroup$Fin n
is used to denote the type of the first n-many non-negative integers; thenFin 0
is empty/uninhabited. $\endgroup$void
is just a misnomer for the unit type. Ifvoid
were uninhabited, it would be impossible to write a function of typeint → void
. $\endgroup$