Swift 4.2: How the weirdest error message led to reimagining implicitly unwrapped optionals

In this tutorial, I’ll show you how researching and learning about the current programming language you’re using (i.e., Swift) can lead you to new discoveries, a better understanding of the language, and becoming a better problem solver. Recently, I ran into a Swift error that at first had me scratching my head. The error had to do with implicitly unwrapped optionals. My debugging and contemporaneous research led me to the little-known fact that, in Swift 4.2, a proposal “to remove the ImplicitlyUnwrappedOptional type from the Swift type system and replace it with an IUO attribute on declarations” was accepted and implemented. Despite the fact that I followed and covered language changes leading to Swift 4.2, I missed this seemingly innocuous but nonetheless prescient modification.

If you’re like me, you’ve still got some code that you haven’t upgraded/ported from Xcode 9 to Xcode 10 — and you’ve got Swift 4.2 changes on your mind because you’ll probably have to port (quite) a few apps to Xcode 10. So there I was the other day, doing something really simple in Xcode 9, and got the weirdest error message. It all had to do with the ImplicitlyUnwrappedOptional type, i.e., in declarations like the following in a Single View App project’s ViewController.swift file:

Implicitly unwrapped optionals

I’ll get to that weird error message, but let’s first review the definition of an implicitly unwrapped optional. That exclamation point immediately following the type, as in UITextField!, means that ageEntryField is an optional, but more specifically, that:

Sometimes it’s clear from a program’s structure that an optional will always have a value, after that value is first set. In these cases, it’s useful to remove the need to check and unwrap the optional’s value every time it’s accessed, because it can be safely assumed to have a value all of the time.

In other words, I can assume that I can get/set the properties of ageEntryField like text without using optional binding (if let). When I set a breakpoint in viewDidLoad() in ViewController.swift and check the value of ageEntryField.text, I see that, at worst, it’s an empty string, and not nil:

That weird error message

Sometimes I like to enhance an app’s user interface interactivity by appending text to a UITextView as data is processed. That way a user can see new data as it’s added and scroll up and down in the text view to review, say, the input or the results of processing that input.

Using Xcode 9, I wrote the following code to append new text to a UITextView:

(I’m using self because this code is contained in a closure.) At first, I was a bit confused when I saw this error message on the second line (click image to enlarge):

The error text was “Cannot convert value of type ‘String!’ to expected argument type ‘inout String’.” Huh? The words “argument” and “inout” imply that I’m calling a function, but I’m just using the += operator for the String type… or am I? The operator in this case is an overload, which is a function (see here how overloading works). Here’s Apple’s documentation on the +=(_:_:) operator for the String type:

Ah, ha!. So I looked at both sides of the statement with the “weird” error, which, by the way, was looking less and less weird:

I know that newEmployeesTextView.text, on the left-hand side, is of type String!. How do I know? I looked it up in the Apple documentation and found it here. Here’s the declaration:

The right-hand side, employeeInfo, is of type String. I wrote the code so I have the declaration of the function that returns data to the constant employeeInfo:

The error arises out of the fact that I’m trying to append a (constant) value of type String on the right-hand side to the value of a variable of type String! on the left-hand side. More accurately described, I’m violating the argument specifications of the +=(_:_:) operator of type String. Remember its declaration:

Now the error message, “Cannot convert value of type ‘String!’ to expected argument type ‘inout String’,” makes perfect sense. If it doesn’t make sense, please leave a comment.

Solving the error

My remedy for the error is quite simple. I’m still appending new text to my UITextView, but I’m using just the = operator:

Swift 4.2 drops the ImplicitlyUnwrappedOptional type

Implicitly unwrapped optionals (IUO) are a solution for providing a Swift language construct for handling, for example, the declaration of UIViewController subclass member properties marked IBOutlet. These properties must be optional because their values cannot be assigned during initialization, but their initialization is required by the Swift language. To provide flexibility, Swift allows us to mark member properties as optional and avoid having an initializer (optional initial values are nil). Outlets are very necessary connections between the view controller in code and the view controller in storyboard. Remember that when you create an IBOutlet in Xcode by control-clicking on a UI component (like UITextView above) and dragging into code, the property is marked as an IUO automatically. An exclamation point (!), a universal sign or warning, designates an IUO, reminding you that there is a bit of risk involved in using optionals.

Remember what Apple has to say about UIViewController. Here we go:

…You rarely create instances of the UIViewController class directly. Instead, you subclass UIViewController and add the methods and properties needed to manage the view controller’s view hierarchy. …

We don’t need an initializer for a UIViewController subclass. An initializer for a UIViewController subclass? What would we do with it? When would we use it? It would be semantically unclear.

It also certainly is expedient to be able to access a member property with an IBOutlet without optional binding.

So what’s the problem with IUOs?
Why all the talk about IUOs, the proposal to remove their type status, and the removal of their status as a type?

While I will provide a brief summary of answers to these questions, I feel its important that you read up on IUOs’ demotion from type status and whether it makes sense or not. I just provided all three relevant links. Have at it. Here’s a quote from an excellent Swift blog post emphasizing that changing IUO status is all about semantic clarity and supporting Swift as it continues to evolve:

Implicitly unwrapped optionals have been reimplemented such that they are no longer a distinct type from Optional. As a result, type checking is more consistent and there are fewer special cases in the compiler. Removing these special cases should lead to fewer bugs in handling of these declarations.

So what happens when I compile my original code in Xcode 10 which has a Swift 4.2 compiler? Remember, here’s my original code that led to the “weird” error message:

There are no compiler errors on that second line of code that invokes the +=(_:_:) operator of type String (click image to enlarge):

Why no error now? Because while the left-hand side, in this specific case, a text property of UITextView, is declared as String!, it matches the +=(_:_:) method’s first argument type of String. If the left-hand side happened to be a String, we would leave it as-is. If the left-hand side happened to be a String? (optional), it would have to be unwrapped with !. The exclamation point (!) is just a marker that provides extra information. As the new Swift 4.2 documentation said, “type checking is more consistent and there are fewer special cases in the compiler,” and furthermore:

However, the appearance of ! at the end of a property or variable declaration’s type no longer indicates that the declaration has IUO type; rather, it indicates that (1) the declaration has optional type, and (2) the declaration has an attribute indicating that its value may be implicitly forced. … Such a declaration is referred to henceforth as an IUO declaration.

Here’s a quote from the official proposal (SE-0054) to “Abolish ImplicitlyUnwrappedOptional type:”

…IUOs are a transitional technology; they represent an easy way to work around un-annotated APIs, or the lack of language features that could more elegantly handle certain patterns of code. As such, we would like to limit their usage moving forward, and introduce more specific language features to take their place. Except for a few specific scenarios, optionals are always the safer bet, and we’d like to encourage people to use them instead of IUOs.

This proposal seeks to limit the adoption of IUOs to places where they are actually required, and put the Swift language on the path to removing implicitly unwrapped optionals from the system entirely when other technologies render them unnecessary. It also completely abolishes any notion of IUOs below the type-checker level of the compiler, which will substantially simplify the compiler implementation.

Swift code changes required by SE-0054
As Swift is a new language, its syntax and semantics will change and will continue to change. I know it’s a pain in the ars to have to upgrade your projects, either manually or using Xcode’s Edit -> Convert -> To Current Swift Syntax…, almost every time a new version of Xcode is released, but that’s the nature of the beast.

I was there when C++ was first commercially released (1985) and have been through major changes in 1989, 1990, 1998, 2005, and 2011.

Swift is a damn good language and I see it gaining much wider acceptance than it already has to date.

You should read up on changes you may need to make to your existing Swift code when you port it to Xcode 10. Read this summary and this one before plunging into upgrading projects in Xcode 10.

Swift’s evolution

I’ve been covering the new features released with Swift 4.2 and Xcode 10, here, here, here, and here, but completely missed any mention of “Reimplementation of Implicitly Unwrapped Optionals.” That’s one reason I posted this article, but my main motivation was in showing you how to learn everything you can about your development environment and become a better problem solver.

Author: Andrew Jaffee

Avid and well-published author, software engineer, designer, and developer, now specializing in iOS mobile app development in Objective-C and Swift, but with a strong background in C#, C++, .NET, JavaScript, HTML, CSS, jQuery, SQL Server, MySQL, Oracle, Agile, Test Driven Development, Git, Continuous Integration, Responsive Web Design, blah, blah, blah ... Did I miss any fad-based catch phrases? My brain avatar was kindly provided by http://icons8.com under a Creative Commons Attribution-NoDerivs 3.0 Unported license.

Leave a Reply

Your email address will not be published. Required fields are marked *