Why Create "Implicitly Unwrapped Optionals", Since That Implies You Know There's a Value

Why create Implicitly Unwrapped Optionals, since that implies you know there's a value?

Consider the case of an object that may have nil properties while it's being constructed and configured, but is immutable and non-nil afterwards (NSImage is often treated this way, though in its case it's still useful to mutate sometimes). Implicitly unwrapped optionals would clean up its code a good deal, with relatively low loss of safety (as long as the one guarantee held, it would be safe).

(Edit) To be clear though: regular optionals are nearly always preferable.

Are implicitly unwrapped optionals truly optionals?

This is a known bug in the swift compiler. Hamish says in a comment this is fixed in a Swift 4.1 snapshot, so it may be fixed in the next Xcode release (9.3).

You can work around this by getting rid of the implicitly-unwrapped optional (IUO), which should be avoided anyway. Depending on why it's currently an IUO, either:

var str: String?
func someFunc(_ x: inout String?) {}
someFunc(&str)

or

var tmp: String?
func someFunc(_ x: inout String?) {}
someFunc(&tmp)
let str = tmp!

I strongly recommend the first, avoid force-unwrapping unless absolutely necessary.

Why do implicitly unwrapped optionals need to unwrapped again in conditionals?

why we need to forcefully unwrap the bool when we use it inside a conditional

It's a historical issue. Once upon a time, in the early days of Swift, an Optional could be used as a condition as a way of asking whether it was nil. There is thus a residual worry that you might think that if willBeSomeBool is a nil test. Therefore you have to either test explicitly for nil or unwrap so that we have a true Bool, thus proving that you know what you're doing — and preventing you from misinterpreting your own results.

Look at it this way. You can't say if willBeSomeString. You can only say something more explicit, either if willBeSomeString == nil or if willBeSomeString == "howdy". So it is simplest to make willBeSomeBool obey that same pattern.

swift - Implicit unwrapped optionals

It's all related to the class initialization.

take Outlets for example they're force unwrapped because we know they will hold a value after initialization from the XIB or Storyboard but they will not be set before the class initialization.

A force unwrapped optional exits to tell the compiler I'm taking the responsibility to make sure this variable will be set before calling it.

in your example I don't think it makes sense to write:

let aString: String! = "this is a test string"

It should just be as you wrote:

let aString: String = "this is a test string"

It makes more sense to have:

var aString: String!

meaning you'll take ownership of this variable initialization (i.e making sure it's not nil)

Why does a `nil` implicitly unwrapped optional print `nil` and not crash?

That does not crash because print accepts Any as the first parameter. Are implicitly unwrapped optionals a kind of Any? Yes they are! Anything is Any. There is no need to unwrap the optional. An implicitly unwrapped optional can be used in a place where Any is expected without unwrapping the optional.

That could potentially be confusing because now you have something with type Any, which doesn't look like it's optional, but it is an optional under the hood. To avoid this, Swift will output a warning telling you that you are implicitly coercing whatever optional type to Any.

You need to use ! to force unwrap it here:

print(x!)

Why are implicitly unwrapped variables now printing out as some(...) in Swift 4.1?

String! is an implicitly unwrapped optional but it's still an optional.

The value will get unwrapped to a non-optional only in situations when it has to be unwrapped, e.g. when being passed to a function that cannot take an optional. However, print can accept an optional and String! will be treated just as String?.

This change actually happened in Swift 3 already as part of SE-0054.

In your example:

var aString: Int!
let aBool = true
if aBool {
aString = 2
}

print(aString)

You should not be using an implicitly unwrapped optional because since it's a var, it get initialized to nil. You should either handle the unassigned case explicitly by using Int?, or, give it a default value:

let aString: Int
let aBool = true
if aBool {
aString = 2
} else {
aString = 0
}

print(aString)

Swift's use of Implicitly Unwrapped Optional before availability of nullability

Apple's frameworks aren't anything special. In the beginning, everything (every object) you used from Objective-C in Swift was an implicitly unwrapped optional. That was because every pointer in Objective-C could possibly return nil.

In fact, even in the era of Objective-C nullability annotations, it's not entirely impossible that a method annotated as nonnull could return nil. Objective-C doesn't enforce the nullability rules, it merely provides a means for annotating your code so that it should be safer to use from Swift. In the case of Apple's frameworks, I'd wager it's a pretty safe bet that you won't have this problem. Or if you do, the next version of Xcode will fix it.

But again, there's nothing special about implicitly unwrapped optionals coming from Objective-C libraries and frameworks. The only thing that an implicitly unwrapped optional tells you is that the framework author has not made the effort to annotate their library yet (you can't leave implicitly unwrapped optionals in an annotated library). And yes, these implicitly unwrapped options can be nil and they can crash your application.

In the case of Apple, if for some reason, you're using say Xcode 7 and Xcode 6 on different projects, if you take something which Xcode 7's update annotations have declared as non-optional, then assuming the implicitly unwrapped optional version in Xcode 6 will never be nil might work out. But if you take something that is an optional in Xcode 7, assuming the implicitly unwrapped version from Xcode 6 will never be nil probably has a decent likelihood of crashing your app.

Ultimately, in Swift, our use of implicitly unwrapped optionals should be few and far between. The primary use of implicitly unwrapped optionals should mostly be reserved for class properties which cannot be set before the class initialization has returned (for example, @IBOutlets in a view controller). Otherwise, they're prone to being the source of numerous "Unexpectedly found nil" questions here on Stack Overflow.


To the question of "Why return an implicitly unwrapped optional rather than an optional?", a few points...

First, that's a language design question. I'm not on the Objective-C or Swift language design team and it's unlikely that anyone from those teams will stop by and answer that question...

Second, that's how the languages are designed to interoperate. Any Objective-C file which has not had nullability annotations added will be treated as if everything is an implicitly unwrapped optional in Swift.

Third, the reason for implicit optionals is it reduces a lot of the verbosity of if let etc statements that optional would require, while not guaranteeing that the variable is actually non-nil. Most of the reason for this is probably because you figure most of these methods actually never return nil.

Fourth, if you know which ones have a chance to be nil and which ones don't, you can actually go ahead and write your Swift code in a way which handles both making assumptions about which way the Objective-C code will be annotated.

For example, with an implicitly unwrapped optional, of course, you can treat it like a non-optional and remove some of the minor verbosity involved with unwrapping.

Additionally, with an implicitly unwrapped optional, if you think it might be nil, all of the optional unwrapping stuff can still work with it.

Example:

override func someFunc(implicitVal: String!) -> String {
return implicitVal ?? "It was nil!"
}

override func someOtherFunc(implicitVal: String!) -> String {
return implicitVal
}

If we assumed them all as optionals, the second example wouldn't work

If we assumed them as non-optionals, the first example wouldn't work.

Implicitly unwrapped optionals allows the freedom for the Swift developer to treat them as either if they make the right assumption about the likelihood of the value being nil.

Why is a Swift implicitly unwrapped optional `nil`?

I'm under the impression that !, the implictly unwrapped optional indicator, is a guarantee that the variable of that type is not nil.

That’s a mis-impression I’m afraid. Implicitly-unwrapped optionals can very much be nil. Only something that isn’t declared with any optional qualifier, neither ? nor !, is guaranteed to be non-nil.

So:

var definitelyCouldBeNilForcedToCheck: String?
var mightBeNilButProbablyNotBECAREFUL: String!
var definitelyNotEverNil: String

There are two use cases for implicitly-unwrapped optionals:

  1. When you are absolutely positively certain that your value won’t be nil, except briefly in very controlled circumstances. For example suppose you have a function that does some processing in its failable initializer. Like this:

    class FileHandler {
    let fileHandle: SomeFileHandleType!

    init?(fileName: String) {
    fileHandle = open(fileName)
    if fileHandle == nil { return nil }
    }

    deinit {
    if fileHandle != nil {
    fileHandle.close()
    }
    }

    func variousMethods() {
    // can just use fileHandle without bothering about
    // unwrapping it, because it cannot possibly be nil
    // based on how you’ve written your code
    }
    }
  2. When you have a massive corpus of Objective-C (lets say, Cocoa or UIKit), and you have no idea when some pointer is returned whether it can be nil or not. And most of the time you think it probably isn’t, and it would be really annoying to make your API users have to unwrap stuff constantly, but then again, you don’t know for certain it can’t be nil and you want them to read the documentation instead. But they’ll probably forget, but what can you do? Eventually you’ll audit all the functions and then make them optionals or non-nullable values.



Related Topics



Leave a reply



Submit