Pattern Matching Optionals.

Assume we have two Optionals, o1 and o2.

Doing this with a mixture of ifs and if lets wouldn’t be super readable.

Pattern matching will express our intent more clearly, and with optional patterns we can still match and unwrap at the same time.

switch (o1, o2) {
case (let v1?, nil):
  print(v1)
// Warning: Immutable value 'v2' was never used; consider replacing with '_' or removing it
case (nil, let v2?):
  doSomething()
default:
  break
}

Nice! This works. But of course there’s a warning, because we’re declaring a useless constant. Let’s just click the fix-it and see what happens.

switch (o1, o2) {
case (let v1?, nil):
  print(v1)
// Warning: 'let' pattern has no effect; sub-pattern didn't bind any variables
case (nil, let _?):
  doSomething()
default:
  break
}

Okay, that’s new. But I guess it makes sense. We’re not letting anything be some value. We just want to match, no need to bind.

Let’s desugar this and see if we can find a better way.

switch (o1, o2) {
case (.Some(let v1), .None):
  print(v1)
// Warning: 'let' pattern has no effect; sub-pattern didn't bind any variables
case (.None, .Some(let _)):
  doSomething()
default:
  break
}

Oh, that did help. After all, we just want to match .Some, whatever the wrapped value. And we know we can use the wildcard pattern _ to match any value, so let’s drop the let altogether.

It’s also clearer now that let a? is just sugar for .Some(let a).

switch (o1, o2) {
case (.Some(let v1), .None):
  print(v1)
case (.None, .Some(_)):
  doSomething()
default:
  break
}

Great, no warnings! But let’s bring the sugar back.

So we know that let a? is sugar for .Some(let a). So what’s the sugary version of .Some(_)?

Yup, it’s _?. Here’s our final version:

switch (o1, o2) {
case (let v1?, nil):
  print(v1)
case (nil, _?):
  doSomething()
default:
  break
}

Nice, concise, and scales nicely to more than two Optionals.