How do I navigate between enum values in EK9?

← Enumerations · Ref: Q220

EK9 enumerations support ++ (increment), -- (decrement), #< (first), and #> (last) operators for navigating between values.

INCREMENT AND DECREMENT

The ++ operator moves to the next declared value. The -- operator moves to the previous. Both are mutating operators that change the variable in place.

BOUNDARY TO UNSET

Incrementing past the last value makes the enum unset. Decrementing before the first value also makes it unset. No ArrayIndexOutOfBounds. No wrap-around confusion. The result is safe, predictable, and testable with the ? operator.

FIRST AND LAST

The #< operator always returns the first declared value. The #> operator always returns the last. These work on any set enum variable and return a set result regardless of which value the variable holds.

SAFE CYCLING

To safely cycle through enum values, check with ? after each increment. When the result becomes unset, you have exhausted all values.

See Q219 for all auto-generated operators. See Q99 for basic enumeration. See Q222 for unset semantics.

Example

defines module qa.enums.navigation

  defines type

    TrafficLight
      Red
      Amber
      Green

  defines program

    EnumNavigationDemo()
      stdout <- Stdout()

      // === INCREMENT THROUGH VALUES ===

      light <- TrafficLight.Red
      stdout.println(`Start: ${light}`)

      light++
      stdout.println(`After ++: ${light}`)

      light++
      stdout.println(`After ++ again: ${light}`)

      // === BOUNDARY: increment past last goes unset ===

      light++
      stdout.println(`Past last isSet: ${light?}`)

      // === DECREMENT THROUGH VALUES ===

      current <- TrafficLight.Green
      stdout.println(`Start: ${current}`)

      current--
      stdout.println(`After --: ${current}`)

      current--
      stdout.println(`After -- again: ${current}`)

      // === BOUNDARY: decrement before first goes unset ===

      current--
      stdout.println(`Before first isSet: ${current?}`)

      // === FIRST AND LAST ===

      mid <- TrafficLight.Amber
      stdout.println(`First: ${#< mid}`)
      stdout.println(`Last: ${#> mid}`)

      // === SAFE CYCLING ===

      item <- TrafficLight.Red
      while item?
        stdout.println(`Cycle: ${item}`)
        item++

Common mistakes

E50060 — EK9 enumerations do not have next() or previous() methods. Use the ++ operator to advance to the next value and -- to go to the previous value. These are mutating operators built into the enum type. See ek9 -h E50060 for details.

Incorrect:

light.next()

Correct:

light++
Other ways to ask this
  • How do increment and decrement work on EK9 enums?
  • What happens when you go past the last enum value?
  • How do I get the first or last enum value in EK9?

Coming from another language?

Java: ordinal() + 1 with manual bounds checking, risk of ArrayIndexOutOfBounds, no built-in next/previous methods. Python: no built-in next or previous on Enum, must use list indexing with manual bounds. Rust: no built-in increment/decrement, must implement manually or use strum crate. Go: can increment iota integer but no bounds safety, wraps silently. C#: can cast to integer and increment but no bounds checking. Kotlin: ordinal + 1 with values() array, manual bounds required. EK9: ++ and -- with automatic boundary-to-unset semantics, completely safe.

Keywords: enumeration, cycle, migrate, increment, decrement, enum, last, navigate, first, unset, previous, boundary, next