Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two (or more) optionals in Swift

While watching an Apple's video about LLDB debugger I found something I can't find an explanation for; he was talking about optional values when he wrote:

var optional: String? = nil; //This is ok, a common optional
var twice_optional: String?? = nil; //What is this and why's this useful??

I opened a playground and started trying it out and realized that you can write as many as ? as you want, and then unwrap them with the same number of !. I understand the concept of wrapping/unwrapping a variable but can't think of a situation where I would like to wrap a value 4, 5 or 6 times.

like image 500
Sherekan Avatar asked Dec 01 '14 09:12

Sherekan


2 Answers

(Updated for Swift >=3)

"Double optionals" can be useful, and the Swift blog entry "Optionals Case Study: valuesForKeys" describes an application.

Here is a simplified example:

let dict : [String : String?] = ["a" : "foo" , "b" : nil]

is a dictionary with optional strings as values. Therefore

let val = dict[key]

has the type String?? aka Optional<Optional<String>>. It is .none (or nil) if the key is not present in the dictionary, and .some(x) otherwise. In the second case, x is a String? aka Optional<String> and can be .none (or nil) or .some(s) where s is a String.

You can use nested optional binding to check for the various cases:

for key in ["a", "b", "c"] {

    let val = dict[key]
    if let x = val {
        if let s = x {
            print("\(key): \(s)")
        } else {
            print("\(key): nil")
        }
    } else {
        print("\(key): not present")
    }

}

Output:

a: foo
b: nil
c: not present

It might be instructive to see how the same can be achieved with pattern matching in a switch-statement:

let val = dict[key]
switch val {
case .some(.some(let s)):
    print("\(key): \(s)")
case .some(.none):
    print("\(key): nil")
case .none:
    print("\(key): not present")
}

or, using the x? pattern as a synonym for .some(x):

let val = dict[key]
switch val {
case let (s??):
    print("\(key): \(s)")
case let (s?):
    print("\(key): nil")
case nil:
    print("\(key): not present")
}

(I do not know a sensible application for more deeply nested optionals.)

like image 52
Martin R Avatar answered Oct 09 '22 15:10

Martin R


var tripleOptional: String???

is same as

var tripleOptional: Optional<Optional<Optional<String>>>

I cannot think of any useful use of it, but its there because optionals are generic work for any type of object. Nested optionals are like box put into another box or array but into an other array.

like image 36
Kirsteins Avatar answered Oct 09 '22 17:10

Kirsteins