11. Enums

Overview

Enums are a special type of class that define a discrete range of possible values:

Enums are declared using the enum positional keyword and must declare their range of values before any other slot declarations:

enum class Color { red, blue, green }

Range

The range of an enum is its discrete set of instances. Each instance of the range has the following characteristics:

The compiler automatically generates two helper slots:

Consider this example to illustrate what happens under the covers:

// what you write
enum class Color { red, blue, green }

// what the compiler generates
class Color : Enum
{
  static const Color red   = make(0, "red")
  static const Color blue  = make(1, "blue")
  static const Color green = make(2, "green")

  static const Color[] vals = [red, blue, green].toImmutable

  static new fromStr(Str s) { ... }

  private new make(Int ord, Str name) : super(ord, name) {}
}

Enum Constructors

Enums can declare their own constructor to initialize additional fields. Remember that an enum is const, which means that all its fields must also be const. This in turn means that all fields must be initialized in the constructor. Enum constructors must be private. The following syntax is used to declare and call an enum constructor:

enum class Suits
{
  clubs("black"),
  diamonds("red"),
  hearts("red"),
  spades("black")

  private new make(Str color) { this.color = color; }

  const Str color;
}

Note that the declaring class doesn't actually manage its own ordinals and names, this is always done by the compiler.

Enum Modifiers

Enums can be annotated with the public or internal modifiers just like classes. It is a compile time error to use the abstract, final, or const modifiers with a enum - final and const are implied.

Reflection

Enums are keyed by both an zero based integer ordinal and a string name. The following summarizes slots often used to work with enums (using Month as an example):

Example code:

apr := Month.apr              // direct access
jun := Month.vals[5]          // lookup by ordinal
aug := Month.fromStr("aug")   // lookup by name
Month.fromStr("bad")          // throws ParseErr
Month.fromStr("bad", false)   // returns null