The implicit unwrapping of an optional boolean - swift

The implicit unwrapping of a Bool type does not seem to work:
var aBoolean: Bool! // nil
aBoolean = false // false
aBoolean // false
aBoolean == true // false
aBoolean == false // true
if aBoolean {
"Hum..." // "Hum..."
} else {
"Normal"
}
if aBoolean! {
"Hum..."
} else {
"Normal" // "Normal"
}
If I had declared aBoolean like var aBoolean: Bool?, this would have been the expected behavior but here, I don't get it.
Is this the correct behavior? I didn't find any doc about it.
Thanks!

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

Not an answer, but if this is indeed the intended behavior with implicitly unwrapped booleans it's rather disturbing. As soon as you use the expression in any logic proposition it will get unwrapped:
var aBoolean: Bool! = false
if !aBoolean {
"I'm unwrapping" // "I'm unwrapping"
}
if aBoolean == false {
"I'm unwrapping" // "I'm unwrapping"
}
Say you have this in your code an at some point your model changes and the condition is reversed, you delete the NOT.
if aBoolean {
"I'm unwrapping" // <- ouch
}
You just got screwed. Makes me want to avoid the implicit unwrapping.

You are making two different truth-checks.
Given:
var aBoolean: Bool! // nil
aBoolean = false // false
if aBoolean {
"Hum..." // "Hum..."
else {
"Normal"
}
if aBoolean! {
"Hum..."
} else {
"Normal" // "Normal"
}
...in the first if aBoolean, the value is not being unwrapped, it is simply testing the optional type to determine if it stores a value.
In the second if aBoolean!, you are testing the truth-value of the unwrapped Bool.
To see that it is indeed being implicitly-unwrapped (when not used in a conditional), try:
println("value of implicitly-unwrapped aBoolean: \(aBoolean)")
...this will print 'true' when aBoolean is set to true, 'false' when it is set to false, and 'nil' when it has not yet been assigned.

Here is the behavior clearly shown:
> var bool1 : Bool!
bool1: Bool! = nil
> bool1 = false
> (bool1 ? "yes" : "no")
$R19: (String) = "yes"
In the above, since bool1 is an optional (which becomes a Some instance), the conditional of simply bool1 evaluates to true (it is not nil).
> var bool2 : Bool = false
bool2: Bool = false
> (bool2 ? "yes" : "no")
$R25: (String) = "no"
When bool2 is not an optional, the conditional of simply bool2 evaluates to false (the value of bool2)

When declaring a variable as "implicitly unwrapped", using the !, it is still an Optional
This type of variable behaves very much like the standard variable type in Objective-C. It can be assigned to nil, but when you access members you do not need to explicitly unwrap it. In this way it is "unsafe" just like in ObjC because you can be accessing properties from nil
Thus, it is used most commonly when bridging from Objective-C. However, it is still an optional, with the only difference being you don't need to unwrap it to access the contents.
I believe this was added mostly to support interop between Swift and Obj-C and might be good practice to sparingly use it in pure Swift code. (Swift guidelines are a fuzzy thing right now and someone might prove me wrong soon!)

Related

Is there an operator in Swift that stops the evaluation of a multi expression conditional statement, as soon as the answer is clear?

In some programming language there is two other operator in addition with simple || and &&. these operators which I am going to call them _orif and _andif from now, can be used in place of && and || and They may help to improve efficiency and avoid errors, because evaluation of the conditional stops as soon as the answer is clear.
For example, evaluation of the following expression will stop halfway through (selectedSprite != nil) is false: So the rest of the conditional will be ignored and never evaluated, this will prevent a fatal error in this case : fatal error: unexpectedly found nil while unwrapping an Optional value and it will raise while reaches to the second expression because obviously nil does not responds to SpriteOwner().
if (selectedSprite != nil) &&
(selectedSprite.SpriteOwner().type == "Human")
{
println("a human selected")
}
I am looking for a replacement for && in above piece of code that could be used instead of the simple && operator, So if the first expression is evaluated as a false one (having the selectedSprite equal to nil) then the second expression be ignored at all.(since it does not have any influence on result)
Question:
Is there such a &&? operator in swift? if the answer is a No,
Is there a better way of doing that instead of nested if statements like I have written here :
if (selectedSprite != nil)
{
if (selectedSprite.SpriteOwner().type == "Human")
{
println("a human selected")
}
}
I am implementing an intelligent system with a lot of if clause in it and most of them are too complicated which adding a new if layer just to control nils is a real nightmare.
What you described is called short circuiting and Swift does have it. For example:
let a : Int? = nil
if a != nil && a! == 1 {
print("a is 1")
} else {
print("a is nil")
}
You can see a is never unwrapped. I think in your case, it's more likely that SpriteOwner() returns nil. the Swifty way to unwrap optional values is to use the let ... where ... syntax:
if let s = selectedSprite where s.SpriteOwner().type == "Human" {
println("a human selected")
}
The binary logical || and && operators in Swift 2 already behave as you describe. See "The Swift Programming Language", under "Logical AND Operator" : https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/BasicOperators.html#//apple_ref/doc/uid/TP40014097-CH6-ID60
If either value is false, the overall expression will also be false. In fact, if the first value is false, the second value won’t even be evaluated, because it can’t possibly make the overall expression equate to true. This is known as short-circuit evaluation.
Try executing the following in a playground; you will see that the second part of the conditional statement is never executed since the first part is false:
func isBar(rv: Bool) -> Bool {
print("side effect of isBar")
return rv
}
func isFoo() -> Bool {
print("side effect of isFoo")
return true
}
if isBar(false) && isFoo() {
print("both true")
}
You could achieve something similar with optional chaining:
class Sprite {
let otherSprite: Sprite?
let type: String
init(otherSprite: Sprite?, type: String) {
self.otherSprite = otherSprite
self.type = type
}
}
let innerSprite = Sprite(otherSprite: nil, type: "Human")
let outerSprite = Sprite(otherSprite: innerSprite, type: "Robot")
This doesn't execute the print statement because they otherSprite? comes back with a nil
if innerSprite.otherSprite?.type == "Human" {
print("A human selected")
}
This will print "A human selected" because the value of otherSprite is non-nil and the type's value == "Human"
if outerSprite.otherSprite?.type == "Human" {
print("A human selected")
}

Error in Apple's Swift documentation on forced unwrapping in if statements?

My iBook on "The Swift Programming Language" contains the following example of a feature describing forced unwrapping in if statements:
let possibleNumber = "123"
let convertedNumber = possibleNumber.toInt()
if convertedNumber {
println("\(possibleNumber) has an integer value of \(convertedNumber!)")
} else {
println("\(possibleNumber) could not be converted to an integer")
}
// prints "123 has an integer value of 123”
But this isn't working for me. Xcode (6.0.1) requires that I explicitly compare with nil as in
if (convertedNumber != nil) {
println("\(possibleNumber) has an integer value of \(convertedNumber!)")
} else {
println("\(possibleNumber) could not be converted to an integer")
}
Is my iBook wrong?
Yes it's wrong or, better, it's outdated. The behavior was changed on the release of 4/8/2014, and you can see the changelog here. The relevant part:
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.
That being said, you can drop the parenthesis
if convertedNumber != nil {
...
}

Swift: logical not operator not working

this piece of code prints two times 'false':
println(levelController?.died)
println(!levelController?.died)
I don't understand why, the levelController is instantiated and the died attribute is declared in LevelController like this:
var died = false
Can someone tell me what I might be doing wrong?
You can create your own not operator like this:
let not = (!)
And now we can assign a bool to test this:
let dead = false
if not(dead) {
print(dead)
// Code
} else {
// Code
}
This is Swift, not Objective C.
levelController?.died is not a boolean value. It is an optional boolean. It can be true, false, or nil. The first println prints false. The logical not operator, applied to an optional, returns false if the optional is not nil, and true if the optional is nil. Just as it does in C when applied to a pointer.
As a complete example, your code:
class Controller {
var died: Bool = false
}
var levelController: Controller? = Controller()
println(levelController?.died)
println(!levelController?.died)
Outputs the following:
Optional(false)
false
The first version of your code levelController?.died makes use of option chaining, unwrapping the levelController and accessing the died property. This explains why the output is Optional(false). You would typically use it as follows:
if let died = levelController?.died {
if (died) {
println("I died")
}
}
The if-let statements unwraps this optional value.
The second version of your code !levelController?.died tests whether the given optional value is nil or not. You will notice that changing died to true of false makes no difference.
However, changing the instantiation as follows:
var levelController: Controller? = nil
Results in !levelController?.died becoming true. This isn't really a terribly practical piece of code!

Swift error: Int is not convertible to 'DictionaryIndex<Int,Int>'

When I switched over from Xcode 6 beta 4 to beta 5 I got this error (Int is not convertible to 'DictionaryIndex') in reference to my plays variable. I don't know how to remedy this.
Here is the code block:
var plays = Dictionary<Int,Int>()
var done = false
var aiDeciding = false
//Function that says what to do if a UIButton is clicked:
#IBAction func UIbuttonClicked(sender:UIButton) {
if !plays[sender.tag] && !aiDeciding && !done {
setImgforCircle(sender.tag, player:1)
thinkingLabel.hidden = true
thinkingLabel2.hidden = true
thinkingLabel3.hidden = true
}
I suppose this is just a deceiving error message and the actual error is in
if !plays[sender.tag]
Instead, it should be
if plays[sender.tag] != nil
This is due to a change in the language, specifically this
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.
plays[sender.tag] returns an Option<Int> and you are assuming that a nil value will evaluate to false, hence !plays[sender.tag].
Since beta 5 this is forbidden and you have to explicitly check against nil
plays[sender.tag] != nil

hasPrefix misbehave on Optional String

Why does the following always print "prefix" which is incorrect but print "no prefix" when String is not optional or implicitly unwrapped optional?
var value:String! = "aaa" // Same incorrect behavior on Optional String as well.
if value?.hasPrefix("bbb") {
NSLog("prefix")
}
else {
NSLog("no prefix")
}
The if statement is checking if the statement returns a value or nil, not if it returns true or false. You can use another if statement to check the value of hasPrefix().
var value:String! = "aaa" // Same incorrect behavior on Optional String as well.
if let hasPrefix = value?.hasPrefix("bbb") {
if hasPrefix{
NSLog("prefix")
}
else {
NSLog("no prefix")
}
}
else {
NSLog("nil value")
}
This is related (not sure if duplicate) of: How to check if Optional is not nil and property is true in one expression?
Summarizing it a bit for your question:
When you use Optional Chaining, the returned value is always an Optional. That means value?.hasPrefix("bbb") returns Bool? and not Bool. Thus, if value is not nil, value?.hasPrefix("bbb") will always not be nil, and so it will go into the first case, no matter if its true or false.
This is explained in the Swift book section on Optional Chaining. It makes sense because when you use Optional Chaining, the return value always has a chance to return nil, and that doesn't depend on the final value in the "chain".
You if statement just gives you an optional result because you are calling the "hasPrefix()" on an optional value.
This wouldn't even work in the newer versions of swift and would give the error :
Value of optional type 'Bool?' not unwrapped; did you mean to use '!'
or '?'?
Refer this for documentation on the same.
Following would give you the required result:
if let val = value, val.hasPrefix("bbb") {
NSLog("prefix")
} else {
NSLog("no prefix")
}