kelan.io

Pattern Matching in an if Statement

Let’s say we have a simple enum like this:

enum State<T> {
    case Waiting
    case Done(result: T)
}

And we want to do something when we have something the .Waiting state.

The Wrong Approach

My first instinct was to write it like this:

let state = State<String>.Waiting  // so we have something to work with in the Playground

if state == .Waiting {
    print("do something")
}

But that didn’t work because it said error: type of expression is ambiguous without more context, because it can’t determine the generic type of T there (even though we’re not doing anything with the .Done case, which is where the associated value of type T actually is). And even if we explicitly tell it the generic type (which would be annoying to do in practice):

if state == State<String>.Waiting {
    print("do something")
}

It still doesn’t work (error: binary operator '==' cannot be applied to two 'State<String>' operands) because State is not Equatable. And we don’t want to make it be Equatable just for this, especially because then we’d have to constrain T to be Equatable. Ugh.

The Proper Solution

Stepping back, what we’re trying to do is see if something is in the .Waiting case, not check for exact equality. That’s what pattern matching is for. So what we really want is to do this:

if case .Waiting = state {
    print("do something")
}

That’s it. Nothing major here – just another small detail on the way to a more Swiftier way of thinking.