Enums in Crystal

Our enumerated type ServerState has an underlying Int32 type.

enum ServerState
  StateIdle
  StateConnected
  StateError
  StateRetrying
end

By implementing the to_s method, values of ServerState can be printed out or converted to strings.

This can get cumbersome if there are many possible values. One might consider a different approach if there are many states.

state_name = {
  ServerState::StateIdle => "idle",
  ServerState::StateConnected => "connected",
  ServerState::StateError => "error",
  ServerState::StateRetrying => "retrying"
}

def to_s(state : ServerState) : String
  state_name[state]
end

If we have a value of type Int32, we cannot pass it to transition - the compiler will complain about type mismatch. This provides some degree of compile-time type safety for enums.

def main : Nil
  ns = transition(ServerState::StateIdle)
  puts to_s(ns)

  ns2 = transition(ns)
  puts to_s(ns2)
end

def transition(s : ServerState) : ServerState
  case s
  when ServerState::StateIdle
    ServerState::StateConnected
  when ServerState::StateConnected, ServerState::StateRetrying
    # Suppose we check some predicates here to determine the next state...
    ServerState::StateIdle
  when ServerState::StateError
    ServerState::StateError
  else
    raise "unknown state: #{s}"
  end
end

main

To run the program, compile the code and execute the compiled binary.

$ crystal run enums.cr
connected
idle