58 Enumerated Types
An enumerated type specifies a set of mutually exclusive possible values. For example, a value
of type PrimaryColor can be red, green or blue:
enum PrimaryColor
{
red,
green,
blue
}
An enum attribute can have an explicit representation-value expression:
enum HttpStatus
{
ok = 200,
notFound = 404,
unavailable = 503
}
The expression must be evaluable at compile time and its value must be an Integer. It may use
anything available in its declaration context, including generic value parameters. For example:
enum Offset<Integer N>
{
first = N,
second,
last = N + 10
}
Explicit representation-value expressions are part of the enum's serialised representation. A
attribute without an explicit expression has the value of the preceding attribute plus one, or zero if there
is no preceding attribute; consequently second above has value N + 1. Attribute names are source labels
for those values and do not determine their representation.
Renaming an attribute does not change its serialised representation when its representation value remains
unchanged for every valid instantiation.
A generic enum introduces a family of enum types. Representation-value expressions are evaluated for each instantiation in that instantiation's generic environment. The resulting values must be distinct and valid for the enum's storage type. Generic constraints may restrict the arguments for which the enum can be instantiated.
Carrier set
An enum declaration introduces a finite named type whose carrier is the set of
declared enum values. For example PrimaryColor has carrier:
carrier(PrimaryColor) = { red, green, blue }
The declared enum values are values of the enum type. Enum values with the same spelling in different enum types are distinct unless the language defines an explicit coercion or identification between them.
Formalisation as a variant with {} attributes
PrimaryColor is formalised as syntactic sugar for:
variant PrimaryColor
{
{} red;
{} green;
{} blue;
}
So each value of an enumerated type is a base attribute of type {}, the empty structural type
described in 47 Structural types.
The attribute can be navigated as a unary path, such as color.red.
Since the result type of such a path is {}, Boolean contexts elaborate it as an existence test,
for example color.red.Σexists.
For every value of the enumerated type, exactly one effective current base attribute has a non-empty extension and every other current base attribute has an empty extension. The selected base attribute's extension contains the single empty structural value. Derived attributes do not participate in this constraint, and dropped base attributes are not current attributes.
Subtyping of enumerated types
Subtyping of enumerated types is possible. A subtype must have a subset of the attributes of its supertype. For example:
enum Color
{
red,
green,
blue,
magenta,
cyan,
yellow
}
enum PrimaryColor isa Color
{
red,
green,
blue
}
This is consistent with subtype as subset.
Every value of type PrimaryColor is a value of type Color.
Storage and serialisation
Every enumerated type has an integer storage type that determines its representation in memory
as well as its serialisation format. The default storage type is Int32.
An enum declaration with no enum supertypes may specify a different fixed-width integer storage type. For example:
enum HttpStatus : Uint16
{
ok = 200,
notFound = 404,
unavailable = 503
}
For every valid instantiation, every representation value, whether explicit or implicit, must be representable by the enum's storage type. This requirement also applies to values retained for dropped attributes and to their replacement values. The storage type is part of the enum's representation contract and cannot be changed as part of 117 Schema evolution.
An enum declaration with one or more enum supertypes cannot specify its own storage type. It inherits the storage type from its supertypes, and all of its enum supertypes must have the same storage type. Consequently, a subtype value has the same physical representation as the corresponding value of each supertype.