Qiulang Qiulang - 7 months ago 25
Swift Question

What are the advantages/use cases of optional patterns introduced in swift 2?

For the simple cases like

if let
or
guard
I don't see the advantage,

if case let x? = someOptional where ... {
...
}

//I don't see the advantage over the original if let

if let x = someOptional where ... {
...
}


For the
for-case-let
case to simplify working with optional collections, I really hope swift can go one step further:

for case let x? in optionalArray {
...
}

//Wouldn't it be better if we could just write

for let x? in optionalArray {
...
}


After google it for a while the only case I find useful is this "Swift 2 Pattern Matching: Unwrapping Multiple Optionals" :

switch (username, password) {
case let (username?, password?):
print("Success!")
case let (username?, nil):
print("Password is missing")
...


So any other advantages of introducing optional patterns?

Answer

I believe you're conflating two different concepts. Admittedly, the syntax isn't immediately intuitive, but I hope their uses are clarified below. (I recommend reading the page about Patterns in The Swift Programming Language.)

case conditions

The "case condition" refers to the ability to write:

  • if case «pattern» = «expr» { ... }
  • while case «pattern» = «expr» { ... }
  • for case «pattern» in «expr» { ... }

These are particularly useful because they let you extract enum values without using switch.

Your example, if case let x? = someOptional ..., is a valid example of this, however I believe it's most useful for enums besides Optional.

enum MyEnum {
    case A
    case B(Int)
    case C(String)
}

func extractStringsFrom(values: [MyEnum]) -> String {
    var result = ""

    // Without case conditions, we have to use a switch
    for value in values {
        switch value {
        case let .C(str):
            result += str
        default:
            break
        }
    }

    // With a case condition, it's much simpler:
    for case let .C(str) in values {
        result += str
    }

    return result
}

You can actually use case conditions with pretty much any pattern that you might normally use in a switch. It can be weird sometimes:

  • if case let str as String = value { ... } (equivalent to if let str = value as? String)
  • if case is String = value { ... } (equivalent to if value is String)
  • if case 1...3 = value { ... } (equivalent to if (1...3).contains(value) or if 1...3 ~= value)

The optional pattern, a.k.a. let x?

The optional pattern, on the other hand, is a pattern that lets you unwrap optionals in contexts besides a simple if let. It's particularly useful when used in a switch (similar to your username/password example):

func doSomething(value: Int?) {
    switch value {
    //case 2:  // Not allowed
    case 2?:
        print("found two")

    case nil:
        print("found nil")

    case let x:
        print("found a different number: \(x)")
    }
}