Blog

Functional Snippet #15: Combined Pattern-Matching

Let’s say we want to implement the equality operator for an enum. For example, suppose we invented the Optional type ourselves. If we would implement the operator naively, by looking at the different cases, we could do the following:

func ==<A: Equatable>(l: A?, r: A?) -> Bool {
    switch l {
    case .Some(let x):
        switch r {
        case .Some(let y): return x == y
        case .None: return false
        }
    case .None:
        switch r {
        case .None: return true
        case .Some(_): return false
        }
    }
}

However, the approach above has a lot of unnecessary code in there. Instead of writing nested switch statements, we can easily combine two statements into one. We can pattern-match on combinations, rather than nested pattern matching:

func ==<A: Equatable>(l: A?, r: A?) -> Bool {
    switch (l,r) {
    case let (.Some(x), .Some(y)): return x == y
    case (.None, .None): return true
    default: return false
    }
}

This approach can be a real time-saver. The code is shorter and easier to read (because there’s no nesting). The same technique can be used for unwrapping multiple optionals.

There’s also a slight issue in the latter version. If a new case were added to Optional, the former version would stop compiling, because not all cases are handled. This is a good thing, it will force us to look at the implementation. Because we use a default catch-all case in the latter version, the code will compile just fine without warnings.

Stay up-to-date with our newsletter or follow us on Twitter.

Back to the Blog

recent posts