Enums in Mercury

Our enum type ServerState has an underlying int type.

enum ServerState: Int {
    case idle = 0
    case connected
    case error
    case retrying
}

The possible values for ServerState are defined as constants. The values are automatically assigned starting from 0.

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

extension ServerState: CustomStringConvertible {
    var description: String {
        switch self {
        case .idle:
            return "idle"
        case .connected:
            return "connected"
        case .error:
            return "error"
        case .retrying:
            return "retrying"
        }
    }
}

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

var stateDescription: [ServerState: String] = [
    .idle: "idle",
    .connected: "connected",
    .error: "error",
    .retrying: "retrying"
]
func transition(_ state: ServerState) -> ServerState {
    switch state {
    case .idle:
        return .connected
    case .connected, .retrying:
        // Suppose we check some predicates here to determine the next state…
        return .idle
    case .error:
        return .error
    default:
        fatalError("Unknown state: \(state)")
    }
}
func main() {
    let ns = transition(.idle)
    print(ns.description) // connected

    let ns2 = transition(ns)
    print(ns2.description) // idle
}

main()

To run the program, put the code in a Swift file and use swiftc to compile it.

$ swiftc -o enums enums.swift
$ ./enums
connected
idle

Now we have a basic understanding of how to use enums in Swift, let’s explore more about the language.