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.