Swift Optionals

This blog post is all about Optionals, a language concept baked into Apple’s Swift programming language. We’ll start off with a practical use case, in which we explain how optionals are used. We will then extend the example to make the code shorter, and hopefully, more readable too. We will finish with a study on optionals and where they come from, for those of you wanting more then just some examples.

Without further ado, let’s start.

What is an Optional?

As found on wikipedia, an Optional (or Option type) represents an encapsulation of an optional value. An optional value either has a value, or it doesn’t. It essentially works as a type-safe alternative for nil.

From Objective C to Swift

We came up with this blogpost, because we tried to understand the deeper concepts behind optionals. We were porting our example application, which we use in many occasions, especially in courses. The first thing we did was porting our very simple model into Swift. The first thing we needed to tackle was how to use optionals in that model. Where is it appropriate to use them, and when is it better to avoid them.

Let’s see what our model looks like in Objective C

//Person.h
@interface Person : NSObject

@property(nonatomic, strong) NSString *identifier;
@property(nonatomic, strong) NSString *firstName;
@property(nonatomic, strong) NSString *lastName;
@property(nonatomic, strong) NSString *realName;
@property(nonatomic, strong) NSString *bio;
@property(nonatomic, strong) NSString *profession;
@property(nonatomic, strong) NSString *websiteUrl;
@property(nonatomic, strong) NSString *imageName;
@property(nonatomic, readonly) NSString *fullName;

@end

//Person.m
@implementation Person

- (NSString *) fullName {
 return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}

@end

If we want to port this model one-on-one to Swift, we have to consider what the Objective C code’s intent is. All properties in this model, except for the fullName, are mutable. This means we can change them at will, and we can set these properties to nil.

So expressed in Swift, we came to this (this example is a mere port, without thinking about improving the code, we have more in store later)

struct Person {
 var identifier: String? = nil
 var firstName: String? = nil
 var lastName: String? = nil
 var realName: String? = nil
 var bio: String? = nil
 var profession: String? = nil
 var websiteUrl: String? = nil
 var imageName: String? = nil
 var fullName: String { return "HOW?" }
}

Let’s take this step by step:

  1. Since all properties were mutable in Objective C, we use “var” for our properties, making them mutable in Swift.
  2. In Objective-C, all properties were essentially nullable, so we use optionals in Swift.1

We skipped the read-only derived full name property, because this is where we started thinking about how to implement this. Lets look at our first attempt.

Read-only properties and nil values

var fullName: String {
 return "\(firstName) \(lastName)"
}

In the next code snippet we show the usage of our person

var p = Person()
println(p.fullName)

//Prints: nil nil

OK, there, same result as in Objective C. However, in Swift, we can probably do better than this. Let’s say we want to use a default firstName and lastName when they are nil. You could argue that we could assign default values to the properties right away, but that wouldn’t solve the problem when we set the values to nil again afterwards anyway. So let’s do it the Swift way.

Taking optionals into account

var fullName: String {
 var result:String;
 if let confirmedFirstName = firstName {
 result = confirmedFirstName
 } else {
 result = "John"
 }
 result += " "
 if let confirmedLastName = lastName {
 result += confirmedLastName
 } else {
 result += "Doe"
 }
 return result
 }

Now the result of printing the full name will be

var p = Person()
println(p.fullName)

//Prints: John Doe

The result is as we want it to be, but the solution is rather verbose. We could try to fit this in ternary operators:

var fullName: String {
 var result:String = (firstName ? firstName! : "John");
 result += " "
 result += (lastName ? lastName! : "Doe")
 return result
}

Shorter (we could even go further and put everything on a single line), but we might argue that readability suffers. To improve this further, we looked at how optionals are implemented in the Swift library.

Optionals behind the scenes

Optional actually is an enum defined like so

//Taken from Apple's Swift library
enum Optional<t> : LogicValue, Reflectable {
 case None
 case Some(T)
 init()
 init(_ some: T)

 /// Allow use in a Boolean context.
 func getLogicValue() -> Bool

 /// Haskell's fmap, which was mis-named
 func map<u>(f: (T) -> U) -> U?
 func getMirror() -> Mirror
}</u></t>

Indeed, if we play with optionals in a playground, an Optional is printed like either nil or {Some "value"} So if optionals are just mere enums, we can use the full power of Swift by using extensions2and even custom operators. We’re close now.

Extending Optional with an extension

Addendum: The next section was written before swift included the The nil coalescing operator. Read on, the excercise is still interesting.
extension Optional {
 func orDefault(defaultValue:T) -> T {
 switch(self) {
 case .None:
 return defaultValue
 case .Some(let value):
 return value
 }
 }
}

Put to use in our fullName getter:

var fullName: String {
 return firstName.orDefault("John") + " " + lastName.orDefault("Doe");
}

This code shows it’s intent, and reads like prose. We could stop here, but let’s see how deep the rabbit hole goes.

Using an operator to get a default value

Let’s try a custom operator to return a default value. 3

operator infix |> {
 associativity left precedence 150
}

@infix func |> <t>(lhs: Optional<t>, rhs: T) -> T {
 return lhs.orDefault(rhs)
}</t></t>

And the new version of the getter becomes:

get {
 return self.firstName |> "John" + " " + self.lastName |> "Doe"
}

The power of Swift is definitely at work here, although we think it might be a bridge too far. We’ll probably stick with just using the orDefault() function.

  1. This might not be what we actually want, but remember, this is a mere port to Swift. We should ask ourselves if these properties are actually optional or not. The essence of an optional is that you force the user of an optional property to always check if it has a value or not, causing bloated code at times. This doesn’t mean we think optionals are bad!
  2. Extensions in Swift are like categories in Objective-C.
  3. Read more on operators here and here