Swift Good Coding Practice: If Statement with Optional Type Bool

Swift good coding practice: If statement with optional type Bool

This is a known issue that is being tracked on the SwiftInFlux repo, which includes this quote from Chris Lattner on the Apple developer forums.

This problem exists with any optional of something that conforms to
the LogicValue protocol (e.g. nested optionals, optional of bool,
etc). We consider it serious issue that needs to be fixed for 1.0 and
have some ideas, but haven't settled on a solution yet.

So, this issue doesn't just effect optional Bools, but any optional type that conforms to the LogicValue protocol (defined as).

protocol LogicValue {
func getLogicValue() -> Bool
}

Anyway as far as recommendations on how to work around this go, it's hard to recommend any one specific solution considering that Apple hasn't given an indication of how they intend to solve this in the future, but I would imagine that continuing to explicitly check the value of the Bool would be the way to go.

if (hero.isAI == true) {
// stuff
}

In fact, after some further reading, the quote listed above continues to read:

For this common case, the simplest answer would be to produce a
warning for "if x" and require someone to explictly write "if x !=
nil" or "if x == true" to make it explicit what they want.

Swift good coding practice: If statement with optional type Bool

This is a known issue that is being tracked on the SwiftInFlux repo, which includes this quote from Chris Lattner on the Apple developer forums.

This problem exists with any optional of something that conforms to
the LogicValue protocol (e.g. nested optionals, optional of bool,
etc). We consider it serious issue that needs to be fixed for 1.0 and
have some ideas, but haven't settled on a solution yet.

So, this issue doesn't just effect optional Bools, but any optional type that conforms to the LogicValue protocol (defined as).

protocol LogicValue {
func getLogicValue() -> Bool
}

Anyway as far as recommendations on how to work around this go, it's hard to recommend any one specific solution considering that Apple hasn't given an indication of how they intend to solve this in the future, but I would imagine that continuing to explicitly check the value of the Bool would be the way to go.

if (hero.isAI == true) {
// stuff
}

In fact, after some further reading, the quote listed above continues to read:

For this common case, the simplest answer would be to produce a
warning for "if x" and require someone to explictly write "if x !=
nil" or "if x == true" to make it explicit what they want.

optional type 'Bool' cannot be used as a boolean; Test for '!=nil' instead

You are checking if the value is different of nil and returning if it is, based un your comments and your second if you probably want to check if it is nil.

println("Checking login details")
if(userEmail.isEmpty || userPassword.isEmpty || userRepeatPassword.isEmpty){
displayMyAlertMessage("All fields are required")
println("Fail to login not all fields where fill")
return
} else if(userPassword != userRepeatPassword){
displayMyAlertMessage("Passwords do not match.")
println("Fail to login password does not match")
} else {
var uiAlert = UIAlertController(title: "Alert", message: "Registration was successful", preferredStyle: UIAlertControllerStyle.Alert)
self.presentViewController(uiAlert, animated: true, completion: nil)
uiAlert.addAction(UIAlertAction(title: "Ok", style: .Default, handler: { action in
dismissViewControllerAnimated(true, completion:nil)
}))
}

The implicit unwrapping of an optional boolean

The first test is checking whether aBoolean stores a value rather than nil, which it does:

if aBoolean {
"Hum..." // "Hum..."
else {
"Normal"
}

The second test is checking against the actual boolean value stored in aBoolean, which is false:

if aBoolean! {
"Hum..."
} else {
"Normal" // "Normal"
}

This is Illustrated in the Swift book in the "Implicitly Wrapped Optionals" section. I think the implicit unwrapping just doesn't apply with if-statements. I agree it is strange but here is the Apple example:

You can still treat an implicitly unwrapped optional like a normal optional, to check if it contains a value:

let assumedString: String! = "An implicitly unwrapped optional string."

if assumedString {
println(assumedString)
}
// prints "An implicitly unwrapped optional string."

Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/us/jEUH0.l

((Any) throws - Bool) throws - OptionalAny') cannot conform to 'BinaryInteger'

With help from @Rob in the comments, I was able to unwrap the message properly and remove unnecessary guard let statements to run my delegate function. Below is the updated piece of code.

  1. Changed message.values.first? as Int as the rate was in an integer format.
  2. Removed guard let statements in converting the heartRate into the double format, as it was non-optional.
extension WatchKitConnection: WCSessionDelegate {

func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
print("didReceiveMessage from watch")
print(message)

// delegate?.updateLatestHeartRate(Double(message.values.first))

guard let heartRate = message.values.first as? Int else {
return
}

let heartRateDouble = Double(heartRate)

print("printing heartRate double from message\(heartRateDouble)")

delegate?.updateLatestHeartRate(heartRateDouble)

print("updateLatestHeartRate")

}
}

Checking the value of an Optional Bool

With optional booleans it's needed to make the check explicit:

if boolean == true {
...
}

Otherwise you can unwrap the optional:

if boolean! {
...
}

But that generates a runtime exception if boolean is nil - to prevent that:

if boolean != nil && boolean! {
...
}

Before beta 5 it was possible, but it has been changed as reported in the release notes:

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.

Addendum: as suggested by @MartinR, a more compact variation to the 3rd option is using the coalescing operator:

if boolean ?? false {
// this code runs only if boolean == true
}

which means: if boolean is not nil, the expression evaluates to the boolean value (i.e. using the unwrapped boolean value), otherwise the expression evaluates to false

Single line if statement in Swift

In Swift the braces aren't optional like they were in Objective-C (C). The parens on the other hand are optional. Examples:

Valid Swift:

if someCondition {
// stuff
}

if (someCondition) {
// stuff
}

Invalid Swift:

if someCondition 
// one liner

if (someCondition)
// one liner

This design decision eliminates an entire class of bugs that can come from improperly using an if statement without braces like the following case, where it might not always be clear that something's value will be changed conditionally, but somethingElse's value will change every time.

Bool something = true
Bool somethingElse = true

if (anUnrelatedCondition)
something = false
somethingElse = false

print something // outputs true
print somethingElse // outputs false

use of let in optional value along with if

Your second code snippet is functionally equivalent to the one from the book. However, the book suggests using let to avoid multiple unwrapping of the optional value.

Since you are checking optionalName for being empty, it is safe to assume that you plan to use it inside the conditional block. When you do so, Swift would need to unwrap the optional value from optionalName again, because the variable remains optional.

When you do the assignment of optionalName to name in the let declaration, the name constant that you get back is not optional. This saves you the unwrap inside the if statement.



Related Topics



Leave a reply



Submit