orome
orome

Reputation: 48436

Why does Swift's optional binding succeed with 'nil' in certain cases?

Apple's Swift language documentation says that optional binding (a.k.a. if let) will "check for a value inside an optional" and "extract that value into" a variable or constant). But this doesn't match what I'm seeing. For example

var x: Int? = nil

if let y1: Int? = x {
    println("y1 = \(y1)") // This is printed, suggesting that x is not checked "inside", but left as Optional(nil) (!= nil)
}

if let y2: Int? = x? {
    println("y2 = \(y2)")
}

if let y3: Int = x? {
    println("y3 = \(y3)")
}

if let y4: Int = x {
    println("y4 = \(y4)")
}

if let y5 = x? {
    println("y5 = \(y5)")
}

if let y6 = x {
    println("y6 = \(y6)")
}

results in (only)

"y1 = nil"

suggesting that no checking "inside" of x is taking place in the y1 case (and that x is left as a wrapped nil, which is not equal to unwrapped nil). The y2 case seems to confirm this by forcing a "check inside" (or is that just optional chaining "taking over"); but there must be more to the story since the y4 and y6 cases also do not print and thus behave as if a "check inside" is happening.

I suspect that there's some insight to be gained from trying

"x = 42"

which results in

"y1 = Optional(42)"
"y2 = Optional(42)"
"y3 = 42"
"y4 = 42"
"y5 = 42"
"y6 = 42"

but if three's some there, it's lost on me.

It seems like (1) the "optional" on the right side of the expression does indeed get "checked inside" if an explicit check is asked for (with ?); but otherwise (2) the left hand side of the expression influences how far "inside" a check is performed (just far enough to make a valid assignment).

How is optional binding working in each of these cases? In particular, when x == nil why does y1 print, and given that it does, why don't y4 and y6 (or generate assignment errors)?

Upvotes: 2

Views: 418

Answers (2)

gnasher729
gnasher729

Reputation: 52530

You assigned an optional Int to an optional Int. The assignment did succeed. It will always succeed, whether the optional Int contained an Int or not.

Upvotes: 1

Steve Rosenberg
Steve Rosenberg

Reputation: 19514

I interpret this differently:

var x: Int? = 1

if let y1: Int = x {
    println("y1 = \(y1)") 
}

//prints y = 1, the optional was checked, contains a value and passes it

var x: Int? = nil

if let y1: Int = x {
    println("y1 = \(y1)") 
}

//does not execute because x does not contain value that can be passed to a non optional y

var x: Int? = nil

if let y1: Int? = x {
    println("y1 = \(y1)")
}
// y = nil, since y is optional and can hold a value of x which is nil, then it passes nil

Optional binding is for checking if an optional contains a value to pass to a non optional parameter.

Upvotes: 2

Related Questions