jsgoupil jsgoupil - 7 months ago 50
Swift Question

What's wrong with comparing non-optional bool in a single if structure in swift

I have been coding in Swift for a while, and I think I had to put a ! on all my let field variables that were not defined immediately.

Now I notice today that this piece of code does not compile and I am really surprised? why is this?

class MyClass : Mapper {
var a: Bool!

required init?(_ map: Map) {
}

// Mappable
func mapping(map: Map) {
a <- map["a"]
}
}

let myClass = MyClass()

if myClass.a { // Compiler not happy
// Optional type 'Bool!' cannot be used as a boolean; test for '!= nil' instead
}

if true && myClass.a { // Compiler happy

}

if myClass.a && myClass.a { // Compiler happy

}


Apple Swift version 2.2

Edit

Some people point out why am I using a
let
for a variable that will never change. I mentioned it is for field variables but I shorten the example. When using ObjectMapper (http://github.com/Hearst-DD/ObjectMapper), all the fields are not defined immediately in the init. This is why they are all either optional? or required!

Answer

A bit of history...

In Swift 1.0, it was possible to check if an optional variable optVar contained a value by just checking:

if optVar {
    println("optVar has a value")
} else {
    println("optVar is nil")
}

In The Swift Programming Language, the update for Swift 1.1 (dated 2014-10-16) stated:

Optionals no longer implicitly evaluate to true when they have a value and false when they do not, to avoid confusion when working with optional Bool values. Instead, make an explicit check against nil with the == or != operators to find out if an optional contains a value.

So, the nonsensical error message that you are getting was put there because the Swift compiler is interpreting your:

if a {
}

to mean:

if a != nil {
}

and it is encouraging you to test against nil to determine if the Optional a has a value.

Perhaps the Swift authors will change it in the future, but for now you will have to explicitly unwrap a:

if a! {
}

or check against true:

if a == true {
}

or (to be completely safe):

if a ?? false {
    print("this will not crash if a is nil")
}