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

10

516

Why would you create a "Implicitly Unwrapped Optional" vs creating just a regular variable or constant? If you know that it can be successfully unwrapped then why create an optional in the first place? For example, why is this:

let someString: String! = "this is the string"

going to be more useful than:

let someString: String = "this is the string"

If ”optionals indicate that a constant or variable is allowed to have 'no value'”, but “sometimes it is clear from a program’s structure that an optional will always have a value after that value is first set”, what is the point of making it an optional in the first place? If you know an optional is always going to have a value, doesn't that make it not optional?

Kiesha answered 3/6, 2014 at 4:9 Comment(0)
S
132

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.

Sudor answered 3/6, 2014 at 4:15 Comment(0)
T
465

Before I can describe the use cases for Implicitly Unwrapped Optionals, you should already understand what Optionals and Implicitly Unwrapped Optionals are in Swift. If you do not, I recommend you first read my article on optionals

When To Use An Implicitly Unwrapped Optional

There are two main reasons that one would create an Implicitly Unwrapped Optional. All have to do with defining a variable that will never be accessed when nil because otherwise, the Swift compiler will always force you to explicitly unwrap an Optional.

1. A Constant That Cannot Be Defined During Initialization

Every member constant must have a value by the time initialization is complete. Sometimes, a constant cannot be initialized with its correct value during initialization, but it can still be guaranteed to have a value before being accessed.

Using an Optional variable gets around this issue because an Optional is automatically initialized with nil and the value it will eventually contain will still be immutable. However, it can be a pain to be constantly unwrapping a variable that you know for sure is not nil. Implicitly Unwrapped Optionals achieve the same benefits as an Optional with the added benefit that one does not have to explicitly unwrap it everywhere.

A great example of this is when a member variable cannot be initialized in a UIView subclass until the view is loaded:

class MyView: UIView {
    @IBOutlet var button: UIButton!
    var buttonOriginalWidth: CGFloat!

    override func awakeFromNib() {
        self.buttonOriginalWidth = self.button.frame.size.width
    }
}

Here, you cannot calculate the original width of the button until the view loads, but you know that awakeFromNib will be called before any other method on the view (other than initialization). Instead of forcing the value to be explicitly unwrapped pointlessly all over your class, you can declare it as an Implicitly Unwrapped Optional.

2. When Your App Cannot Recover From a Variable Being nil

This should be extremely rare, but if your app can not continue to run if a variable is nil when accessed, it would be a waste of time to bother testing it for nil. Normally if you have a condition that must absolutely be true for your app to continue running, you would use an assert. An Implicitly Unwrapped Optional has an assert for nil built right into it. Even then, it is often good to unwrap the optional and use a more descriptive assert if it is nil.

When Not To Use An Implicitly Unwrapped Optional

1. Lazily Calculated Member Variables

Sometimes you have a member variable that should never be nil, but it cannot be set to the correct value during initialization. One solution is to use an Implicitly Unwrapped Optional, but a better way is to use a lazy variable:

class FileSystemItem {
}

class Directory : FileSystemItem {
    lazy var contents : [FileSystemItem] = {
        var loadedContents = [FileSystemItem]()
        // load contents and append to loadedContents
        return loadedContents
    }()
}

Now, the member variable contents is not initialized until the first time it is accessed. This gives the class a chance to get into the correct state before calculating the initial value.

Note: This may seem to contradict #1 from above. However, there is an important distinction to be made. The buttonOriginalWidth above must be set during viewDidLoad to prevent anyone changing the buttons width before the property is accessed.

2. Everywhere Else

For the most part, Implicitly Unwrapped Optionals should be avoided because if used mistakenly, your entire app will crash when it is accessed while nil. If you are ever not sure about whether a variable can be nil, always default to using a normal Optional. Unwrapping a variable that is never nil certainly doesn't hurt very much.

Tarrah answered 5/7, 2014 at 5:3 Comment(23)
This answer should be updated for beta 5. You can no longer use if someOptional.Loire
Hmmm... shouldn't it be if (image != nil)? I don't know where you got .hasValue from...Loire
@SantaClaus hasValue is defined right on Optional. I prefer the semantics of hasValue to those of != nil. I feel it is much more understandable for new programers who have not used nil in other languages. hasValue is much more logical than nil.Tarrah
Oh wow, Xcode doesn't even suggest hasValue. Ex if you type "has" it doesn't suggest hasValue. (however it does suggest hashValue, which isn't any use here.)Loire
@SantaClaus looks like a bug should be reported. I assume it is because autocomplete is coming from the underlying UIImage instead of the optionalTarrah
Hmmm, is .hasValue documented anywhere? I can't seem to find anything.Loire
@SantaClaus, no I don't. Regardless, it is self explanatory, compiles, and functions correctly. If they remove it I will revert to using nil, but I still prefer it this way.Tarrah
What I'm getting at is where did you find that the .hasValue even exists?Loire
@SantaClaus, I honestly don't remember. Probably either a circumstance where the autocomplete did work, or from just looking at the Optional definition in Xcode.Tarrah
Looks like hasValue was pulled from beta 6. Ash put it back though... github.com/AshFurrow/hasValueUnchancy
"Technically, all initializers from classes that inherit from NSObject return Implicitly UnwrappedOptionals." This is not true. Swift thinks that all initializers (from ObjC or not) return non-optional. If an ObjC initializer returns nil, Swift does not handle it correctly and it is a bug, for which assigning to an optional is a workaround. To demonstrate the point, If you assign the result of an initializer that returns nil to a non-optional variable it does not crash, as you would expect if the initializer returned implicitly-unwrapped optional. However, using that variable later crashesCorporation
"When Your App Cannot Recover From a Variable Being nil ..." I would argue that, if the program is going to fail if it's nil anyway, why not make it non-optional and not let it be nil, and let the program fail earlier, by forcibly unwrapping it in whatever place assigns into this variable?Corporation
Is this statement true? "The values contained in an Implicitly Unwrapped Optional (or even an Optional) cannot be mutated. You can change the value that is stored within it, but never modify it." I tried and can modify it just fineWeatherford
@Boon, Thank you for pointing that out. This was a change in beta 5 that Implicitly Unwrapped Optionals are now mutable. I updated my answer to fix this.Tarrah
@Corporation Regarding the return type of Objc initializers, it is more of an implicit Implicitly Unwrapped Optional. The behavior you described for using a "non-optional" is exactly what an Implicitly Unwrapped Optional would do (not fail until being accessed). Regarding letting the program fail earlier by forcibly unwrapping, I agree that using a non-optional is preferred, but this is not always possible.Tarrah
@drewag: I think you're misunderstanding what I said. When you assign an optional that is nil to a non-optional, it crashes on that line, which makes sense, because there is an unwrapping there. Do you not agree? This is the behavior I see in an actual program and what it should be according to the language guide. However, assigning the result of an initializer that returns nil to a non-optional does not crash on that line.Corporation
@newacct, in my testing, assigning a non-optional to the result of an initializer that returns nil does crash: var image = UIImage(named: "non-existent") creates a EXC_BAD_ACCESSTarrah
@drewag: that line, without any further uses of image, does not crash for me, on debug on beta 6 (haven't tried beta 7 yet)Corporation
@Corporation ya I don't know. It crashes in a playground but not in an app.Tarrah
I still don't understand the following sentence. Can anyone elaborate on it? Note: This may seem to contradict #1 from above. However, there is an important distinction to be made. The buttonOriginalWidth above must be set during viewDidLoad to prevent anyone changing the buttons width before the property is accessed.With
All legitimate use cases of implicitly unwrapped optionals appear to be related to Objective-C carryovers or the view controller lifecycle. But the V.C.L. is inelegant enough already. In other words, this all I.U.O. seems like a problem that will go away when Swift and Cocoa are improved.Laurentian
Please note that many Objective-C NSObject inits are actually Optionals and not Implicitly Unwrapped Optionals.Atlee
you said: "but you know that viewDidLoad will be called before any other method on the view" but your code is using awakeFromNib which is slightly confusing. Should your be saying: "but you know that viewDidLoad/awakeFromNib..."Verticillaster
S
132

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.

Sudor answered 3/6, 2014 at 4:15 Comment(0)
L
56

Implicitly unwrapped optionals are useful for presenting a property as non-optional when really it needs to be optional under the covers. This is often necessary for "tying the knot" between two related objects that each need a reference to the other. It makes sense when neither reference is actually optional, but one of them needs to be nil while the pair is being initialized.

For example:

// These classes are buddies that never go anywhere without each other
class B {
    var name : String
    weak var myBuddyA : A!
    init(name : String) {
        self.name = name
    }
}

class A {
    var name : String
    var myBuddyB : B
    init(name : String) {
        self.name = name
        myBuddyB = B(name:"\(name)'s buddy B")
        myBuddyB.myBuddyA = self
    }
}

var a = A(name:"Big A")
println(a.myBuddyB.name)   // prints "Big A's buddy B"

Any B instance should always have a valid myBuddyA reference, so we don't want to make the user treat it as optional, but we need it to be optional so that we can construct a B before we have an A to refer to.

HOWEVER! This sort of mutual reference requirement is often an indication of tight coupling and poor design. If you find yourself relying on implicitly unwrapped optionals you should probably consider refactoring to eliminate the cross-dependencies.

Laager answered 3/6, 2014 at 22:44 Comment(6)
I think one of the reasons they created this language feature is @IBOutletChrismatory
+1 for the "HOWEVER" caveat. It may not be true all the time, but it's certainly something to look out for.Analemma
You still have a strong reference cycle between A and B. Implicitly unwrapped optionals DO NOT create a weak reference. You still need to declare myByddyA or myBuddyB as weak (probably myBuddyA)Tarrah
To be even more clear why this answer is wrong and dangerously misleading: Implicitly Unwrapped Optionals have absolutely nothing to do with memory management and do not prevent retain cycles. However, Implicitly Unwrapped Optionals are still useful in the circumstance described for setting up the two way reference. So simply adding the weak declaration and removing "without creating a strong retain cycle"Tarrah
@drewag: You're right -- I've edited the answer to remove the retain cycle. I intended to make the backreference weak but I guess it slipped my mind.Laager
This is a slightly modified version of Apple's own documentation found here: Automatic Reference Counting. The entire article is a must read. To find the part the specifically addresses the question search that page for Unowned References and Implicitly Unwrapped Optional PropertiesVerticillaster
C
39

Implicitly unwrapped optionals are pragmatic compromise to make the work in hybrid environment that has to interoperate with existing Cocoa frameworks and their conventions more pleasant, while also allowing for stepwise migration into safer programing paradigm — without null pointers — enforced by the Swift compiler.

Swift book, in The Basics chapter, section Implicitly Unwrapped Optionals says:

Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter. The primary use of implicitly unwrapped optionals in Swift is during class initialization, as described in Unowned References and Implicitly Unwrapped Optional Properties.

You can think of an implicitly unwrapped optional as giving permission for the optional to be unwrapped automatically whenever it is used. Rather than placing an exclamation mark after the optional’s name each time you use it, you place an exclamation mark after the optional’s type when you declare it.

This comes down to use cases where the non-nil-ness of properties is established via usage convention, and can not be enforced by compiler during the class initialization. For example, the UIViewController properties that are initialized from NIBs or Storyboards, where the initialization is split into separate phases, but after the viewDidLoad() you can assume that properties generally exist. Otherwise, in order to satisfy the compiler, you had to be using the forced unwrapping, optional binding or optional chaining only to obscure the main purpose of the code.

Above part from the Swift book refers also to the Automatic Reference Counting chapter:

However, there is a third scenario, in which both properties should always have a value, and neither property should ever be nil once initialization is complete. In this scenario, it is useful to combine an unowned property on one class with an implicitly unwrapped optional property on the other class.

This enables both properties to be accessed directly (without optional unwrapping) once initialization is complete, while still avoiding a reference cycle.

This comes down to the quirks of not being a garbage collected language, therefore the breaking of retain cycles is on you as a programmer and implicitly unwrapped optionals are a tool to hide this quirk.

That covers the “When to use implicitly unwrapped optionals in your code?” question. As an application developer, you’ll mostly encounter them in method signatures of libraries written in Objective-C, which doesn’t have the ability to express optional types.

From Using Swift with Cocoa and Objective-C, section Working with nil:

Because Objective-C does not make any guarantees that an object is non-nil, Swift makes all classes in argument types and return types optional in imported Objective-C APIs. Before you use an Objective-C object, you should check to ensure that it is not missing.

In some cases, you might be absolutely certain that an Objective-C method or property never returns a nil object reference. To make objects in this special scenario more convenient to work with, Swift imports object types as implicitly unwrapped optionals. Implicitly unwrapped optional types include all of the safety features of optional types. In addition, you can access the value directly without checking for nil or unwrapping it yourself. When you access the value in this kind of optional type without safely unwrapping it first, the implicitly unwrapped optional checks whether the value is missing. If the value is missing, a runtime error occurs. As a result, you should always check and unwrap an implicitly unwrapped optional yourself, unless you are sure that the value cannot be missing.

...and beyond here lay dragons

Coverdale answered 12/6, 2014 at 14:6 Comment(2)
Thanks for this thorough answer. Can you think of a quick checklist of when to use an Implicitly Unwrapped Optionals and when a standard variable would suffice?Berkin
@Berkin I added my own answer with a list and concrete examplesTarrah
F
19

One-line (or several-line) simple examples don't cover the behavior of optionals very well — yeah, if you declare a variable and provide it with a value right away, there's no point in an optional.

The best case I've seen so far is setup that happens after object initialization, followed by use that's "guaranteed" to follow that setup, e.g. in a view controller:

class MyViewController: UIViewController {

    var screenSize: CGSize?

    override func viewDidLoad {
        super.viewDidLoad()
        screenSize = view.frame.size
    }

    @IBAction printSize(sender: UIButton) {
        println("Screen size: \(screenSize!)")
    }
}

We know printSize will be called after the view is loaded — it's an action method hooked up to a control inside that view, and we made sure not to call it otherwise. So we can save ourselves some optional-checking/binding with the !. Swift can't recognize that guarantee (at least until Apple solves the halting problem), so you tell the compiler it exists.

This breaks type safety to some degree, though. Anyplace you have an implicitly unwrapped optional is a place your app can crash if your "guarantee" doesn't always hold, so it's a feature to use sparingly. Besides, using ! all the time makes it sound like you're yelling, and nobody likes that.

Farrahfarrand answered 3/6, 2014 at 4:26 Comment(4)
Why not just initialize screenSize to CGSize(height: 0, width: 0) and save the trouble of having to yell the variable every time you access it?Wester
A size might not have been the best example, since CGSizeZero can be a good sentinel value in real-world usage. But what if you have a size loaded from nib that might actually be zero? Then using CGSizeZero as a sentinel doesn't help you distinguish between a value being unset and being set to zero. Moreover, this applies equally well to other types loaded from nib (or anywhere else after init): strings, references to subviews, etc.Farrahfarrand
Part of the point of Optional in functional languages is to not have sentinel values. You either have a value or you don't. You shouldn't have a case where you have a value that indicates a missing value.Outworn
I think you've misunderstood the OP's question. The OP isn't asking about the general case for optionals, rather, specifically about the need/use of implicitly unwrapped optionals (i.e. not let foo? = 42, rather let foo! = 42). This doesn't address that. (This may be a relevant answer about optionals, mind you, but not about implicitly unwrapped optionals which are a different/related animal.)Analemma
J
15

Apple gives a great example in The Swift Programming Language -> Automatic Reference Counting -> Resolving Strong Reference Cycles Between Class Instances -> Unowned References and Implicitly Unwrapped Optional Properties

class Country {
    let name: String
    var capitalCity: City! // Apple finally correct this line until 2.0 Prerelease (let -> var)
    init(name: String, capitalName: String) {
        self.name = name
        self.capitalCity = City(name: capitalName, country: self)
    }
}

class City {
    let name: String
    unowned let country: Country
    init(name: String, country: Country) {
        self.name = name
        self.country = country
    }
}

The initializer for City is called from within the initializer for Country. However, the initializer for Country cannot pass self to the City initializer until a new Country instance is fully initialized, as described in Two-Phase Initialization.

To cope with this requirement, you declare the capitalCity property of Country as an implicitly unwrapped optional property.

Jeopardy answered 17/8, 2015 at 9:47 Comment(1)
The tutorial mentioned in this answer is here.Wexler
S
3

The rationale of implicit optionals is easier to explain by first looking at the rationale for forced unwrapping.

Forced unwrapping of an optional (implicit or not), using the ! operator, means you're certain that your code has no bugs and the optional already has a value where it is being unwrapped. Without the ! operator, you would probably just assert with an optional binding:

 if let value = optionalWhichTotallyHasAValue {
     println("\(value)")
 } else {
     assert(false)
 }

which is not as nice as

println("\(value!)")

Now, implicit optionals let you express having an optional which you expect to always to have a value when unwrapped, in all possible flows. So it just goes a step further in helping you - by relaxing the requirement of writing the ! to unwrap each time, and ensuring that the runtime will still error in case your assumptions about the flow are wrong.

Seidel answered 3/6, 2014 at 22:59 Comment(1)
@Corporation : non-nil in all possible flows through your code is not the same as non-nil from parent (class/struct) initialization through deallocation. Interface Builder is the classic example (but there are lots of other delayed initialization patterns): if a class is only ever used from a nib, then outlet variables won't be set in init (which you might not even implement), but they're guaranteed to be set after awakeFromNib / viewDidLoad.Farrahfarrand
S
3

If you know for sure, a value return from an optional instead of nil, Implicitly Unwrapped Optionals use to directly catch those values from optionals and non optionals can't.

//Optional string with a value
let optionalString: String? = "This is an optional String"

//Declaration of an Implicitly Unwrapped Optional String
let implicitlyUnwrappedOptionalString: String!

//Declaration of a non Optional String
let nonOptionalString: String

//Here you can catch the value of an optional
implicitlyUnwrappedOptionalString = optionalString

//Here you can't catch the value of an optional and this will cause an error
nonOptionalString = optionalString

So this is the difference between use of

let someString : String! and let someString : String

Subversive answered 14/1, 2017 at 16:52 Comment(1)
This doesn't answer the OP's question. OP knows what an Implicitly Unwrapped Optional is.Wexler
T
2

Implicitly Unwrapped Optional(IUO)

It is a syntactic sugar for Optional that does not force a programmer to unwrap a variable. It can be used for a variable which can not be initialised during two-phase initialization process and implies non-nil. This variable behaves itself as non-nil but actually is an optional variable. A good example is - Interface Builder's outlets

Optional usually are preferable

var implicitlyUnwrappedOptional: String! //<- Implicitly Unwrapped Optional
var nonNil: String = ""
var optional: String?

func foo() {
    //get a value
    nonNil.count
    optional?.count
    
    //Danderour - makes a force unwrapping which can throw a runtime error
    implicitlyUnwrappedOptional.count
    
    //assign to nil
//        nonNil = nil //Compile error - 'nil' cannot be assigned to type 'String'
    optional = nil
    implicitlyUnwrappedOptional = nil
}
Timmerman answered 21/3, 2020 at 20:41 Comment(0)
R
0

I think Optional is a bad name for this construct that confuses a lot of beginners.

Other languages (Kotlin and C# for example) use the term Nullable, and it makes it a lot easier to understand this.

Nullable means you can assign a null value to a variable of this type. So if it's Nullable<SomeClassType>, you can assign nulls to it, if it's just SomeClassType, you can't. That's just how Swift works.

Why use them? Well, sometimes you need to have nulls, that's why. For example, when you know that you want to have a field in a class, but you can't assign it to anything when you are creating an instance of that class, but you will later on. I won't give examples, because people have already provided them on here. I'm just writing this up to give my 2 cents.

Btw, I suggest you look at how this works in other languages, like Kotlin and C#.

Here's a link explaining this feature in Kotlin: https://kotlinlang.org/docs/reference/null-safety.html

Other languages, like Java and Scala do have Optionals, but they work differently from Optionals in Swift, because Java and Scala's types are all nullable by default.

All in all, I think that this feature should have been named Nullable in Swift, and not Optional...

Ravenravening answered 13/7, 2019 at 10:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.