How do I create an enumeration in EK9?

← Classes and OOP · Ref: Q99

Enumerations are defined under 'defines type' with a value list. They automatically get 24 operators and 3 constructors with no boilerplate.

BASIC ENUMERATION

  defines type
    Season
      Spring, Summer, Autumn, Winter

Values ordered by declaration.

AUTOMATIC OPERATORS (24 + 3 constructors)

  Comparison: ==, <>, <, >, <=, >=, <=> (same-type and String)
  Conversion: $ (String), #^ (promote), $$ (JSON)
  Hash/Set: #?, ?
  First/Last: #<, #>
  Constructors: Season() (unset), Season(Season) (copy), Season(String) (from string)

TRI-STATE

  Season() is unset. Season("Invalid") returns unset. ? checks state. No exceptions on invalid input.

ITERATION

  for season in Season

Or: cat Season > stdout, cat Season | collect as List of Season.

SWITCH

Compiler requires all enum values listed in cases (E07310). Duplicates detected (E02060).

NO METHODS

Enums are pure value types. No methods, fields, or custom constructors. Use functions for behaviour, Dicts for associated data.

See Q73 for exhaustive switch. See Q96 for operators. See Q100 for Java comparison. See Q219 for free operators. See Q223 for constrained enums. See Q224 for enum streams. See Q238 for the fixed operator set.

Example

defines module qa.oop.enumeration

  defines type

    Season
      Spring
      Summer
      Autumn
      Winter

  defines function

    describeSeason() as pure
      -> season as Season
      <- description <- String()

      switch season
        case Season.Spring
          description: "flowers bloom"
        case Season.Summer
          description: "warm and sunny"
        case Season.Autumn
          description: "leaves falling"
        case Season.Winter
          description: "cold and snowy"
        default
          description: "no season set"

  defines program

    EnumerationDemo()
      stdout <- Stdout()

      // === BASIC ENUMERATION: qualified access ===

      favourite <- Season.Summer
      stdout.println(`Favourite: ${favourite}`)

      // === AUTOMATIC COMPARISON OPERATORS ===

      stdout.println(`Spring < Winter: ${Season.Spring < Season.Winter}`)
      stdout.println(`Summer == Summer: ${Season.Summer == Season.Summer}`)

      // === STRING COMPARISON: enum vs String directly ===

      stdout.println(`Direct string compare: ${favourite == "Summer"}`)

      // === FIRST AND LAST ===

      stdout.println(`First: ${#< favourite}`)
      stdout.println(`Last: ${#> favourite}`)

      // === CONVERSION: $, #? ===

      asString <- $favourite
      stdout.println(`As string: ${asString}`)
      stdout.println(`Hash: ${#?favourite}`)

      // === TRI-STATE: unset enumerations ===

      unset <- Season()
      stdout.println(`Unset isSet: ${unset?}`)

      // === STRING CONSTRUCTION: safe, no exceptions ===

      fromString <- Season("Autumn")
      stdout.println(`From valid string: ${fromString}`)

      invalid <- Season("Monsoon")
      stdout.println(`From invalid string isSet: ${invalid?}`)

      // === GUARD EXPRESSION: safe string parsing ===

      if parsed <- Season("Winter")
        stdout.println(`Parsed: ${parsed}`)

      // === ITERATION: for...in ===

      stdout.println("All seasons:")
      for season in Season
        stdout.println(`  ${season}: ${describeSeason(season)}`)

      // === STREAM PIPELINE ===

      seasons <- cat Season | collect as List of Season
      stdout.println(`Count: ${length seasons}`)

      // === STREAM TO OUTPUT ===

      stdout.println("Streamed:")
      cat Season > stdout

      // === SWITCH WITH MULTIPLE CASE VALUES ===

      for season in Season
        category <- switch season
          <- rtn as String: String()
          case Season.Spring, Season.Summer
            rtn: "warm half"
          case Season.Autumn, Season.Winter
            rtn: "cold half"
          default
            rtn: "unknown"
        stdout.println(`${season} is ${category}`)

Common mistakes

E07630 — The $ operator works on enumeration INSTANCES, not the enumeration TYPE. Use $ on variables like $favourite, not on the type name Season. See ek9 -h E07630 for details.

Incorrect:

$Season

Correct:

$favourite

E01050 — EK9 normalizes enumeration names (uppercase + remove underscores) to detect confusing duplicates. Spring and SPRING both normalize to SPRING, triggering E01050. Use clearly distinct names. See ek9 -h E01050 for details.

Incorrect:

Spring
      Summer
      SPRING
      Winter

Correct:

Spring
      Summer
      Autumn
      Winter

E07310 — When switching on an enumeration, the compiler requires all values to be explicitly listed in case clauses. Removing Autumn and Winter cases leaves the switch non-exhaustive, triggering E07310. See ek9 -h E07310 for details.

Incorrect:

default

Correct:

case Season.Autumn
          description: "leaves falling"
        case Season.Winter
          description: "cold and snowy"
        default

E02060 — Duplicate enumeration values in switch cases are detected at compile time. Replacing Autumn with a second Spring creates a duplicate, triggering E02060. See ek9 -h E02060 for details.

Incorrect:

case Season.Spring
          description: "flowers bloom"

Correct:

case Season.Autumn
          description: "leaves falling"
Other ways to ask this
  • What is the syntax for enums in EK9?
  • How do EK9 enumerations work?
  • How do I define an enum type in EK9?
  • What operators do enumerations get automatically?

Coming from another language?

Java: enum valueOf() throws on invalid. Python: Enum['NAME'] raises KeyError. Go: iota constants, no type safety. EK9: value list, 24 auto operators, invalid string returns unset, for...in iteration, no methods.

Keywords: composition, hashcode, enum, string, stream, enumeration, switch, unset, automatic, type, comparison, last, constructor, value, operator, pipeline, first, iteration, JSON, tri-state