I think that enum
declarations can be useful to get the number of elements in the set right.
Consider
enum TwoValues { First, Second }
The type TwoValues
has two values, those are TwoValues::First
and TwoValues::Second
. Describing the set of all value of type TwoValues
, that’s a 2-element set,
{TwoValues::First
, TwoValues::Second
}
Conveniently, the enum
declaration itself already almost looks like this set: { First, Second }
.
Next example, going lower:
enum OneValue { First }
well, that’s a type with a single value. Every instance of OnceValue
will be OneValue::First
, while the value of type TwoValues
can be represented with 1 bit of data, a value of type OneValue
needs 0 bits of data. Thus it’s a zero-sized type, still the set of values isn’t a 0-element set, but a 1-element set, namely the set
{OneValue::First
}
Going lower:
enum ZeroValues { }
now that’s an enum without any values at all. You cannot construct a value of type ZeroValues
. If a function promises “if I return, then I return a value of type ZeroValues
”, then you know that that function will never return. Because values of type ZeroValues
don’t exist. The set of all value of type ZeroValues
exists: It’s the set
{ }
or sometimes written
∅
so the “empty set”. The fact that no values of ZeroValues
exists then corresponds to the fact that no elements of the empty set exist. The set itself exists, but elements of it don’t.
Comparing these enums with more canonical types from the Rust standard library, we’d have
the type TwoValues
is like the type bool
,
the value TwoValues::First
corresponds to the value false
,
the value TwoValues::Second
corresponds to the value true
,
the type OneValue
is like the type ()
the value OneValue::First
corresponds to the value the value ()
,
the type ZeroValues
is like the type !