Swift optional

Optional type in Swift handles the absence of a value. Optional say either "there is a value, and it equals x" or "there isn't a value at all".

Swift optional

Optional type in Swift handles the absence of a value. Optional say either "there is a value, and it equals x" or "there isn't a value at all".

To understand about optional type we must know about type safety and type inference and how they are being used combinedly in Swift.

Type Safety

Swift is a type-safe language. A type safe language encourages us to be clear about the types of values our code can work with. If part of our code expects a String, we can’t pass it an Int by mistake.

var message: String
/// This will throw a compiletime error stating "Can not assign value of type 'Int' to type 'String'". Because we already specified that it's going to be a String.
message = 22

Type Inference

If we don’t specify the type of value we need, Swift uses type inference to work out the appropriate type. Type inference enables a compiler to deduce the type of a particular expression automatically when it compiles our code, simply by examining the values we provide.

/// Variable 'n' is inferred to be of type 'Int'.
var n = 9
/// It will work, because 11 is an 'Int'.
n = 11

Type Safety & Type Inference together

/// 'Type inference' will happen here, we won't specify that this is an 'Int', the compiler itself will find out.
var n = 9
/// It will work, because 11 is an 'Int'.
n = 11
/// Because of 'Type Safety' ability we will get an error message stating: "Can not assign value of type 'Int' to type 'String'".
n = "Hello world"

Let's understand optional type by an example

An optional data type allows nil to be a value for a variable or constant.

In Swift whenever we use a variable we write var n = 0 or var greet = "Hello" this style of using variable is known as defining variable.

However there are instances when we do not have a clear definition of a variable in very early stage of the program and want the variable to have a value at some later stage of the program, this style of using variable is also known as declaring variable.

Well using optional we can create a simillar situation where we declare variable or constant without assigning something to it at first, in which case it is empty. To define emptyness Swift offers a reserved keyword called nil, which stands for empty or nothing.

Hence, if we don't want to assign acutal data to our variable at first we can write var n = nil and that means that the variable contains nothing. However it will still throw compile time error stating "nil requires a contextual type". Here we assigned nil at the first place which means empty and there is no data type for empty, thus variable n doesn't have any data type and it does not follow the type safety and type inference norms.

In Swift, none of the data types include nil as a valid value. Hence nil is not a valid value for Int, String or any data type variable in Swift. That's why we can not assign nil to a Int, String or any data type variable.

Well this is where Optionals came in to picture by adding ? to the data type as var n: Int? = nil makes it an Optional variable of type Int, which means that the variable n can either be an Int or nil.

We set an optional variable to a valueless state by assigning it the special value nil:

/// n contains an actual `Int` value of 9
var n: Int? = 9
/// n now contains no value
n = nil

If we define an optional variable without providing a default value, the variable is automatically set to nil for us:

/// greeting is automatically set to `nil`
var greeting: String?

An optional is an enum of two cases

An Optional is a type on its own, actually one of Swift's super-powered enums. It has two possible values, None and Some(T), where T is an associated value of the correct data type available in Swift.

However, instead of using the .none case we can use nil to indicate the absence of a value.

enum Optional<Wrapped> {
    /// The absence of a value.
    case none

    /// The presence of a value, stored as `Wrapped`.
    case some(Wrapped)
}

Thus, we can define the above greeting variable as optional as well by using the enum:

let greeting = Optional.some("Hello world!")
print(greeting!.count)

How to find out whether an optional contains a value or not?

Optional binding is used to find out whether an optional contains a value, and if so, to make that value available as a temporary constant or variable. Optional binding can be used with if and while statements to check for a value inside an optional, and to extract that value into a constant or variable, as part of a single action.

var n: Int? = nil
if ((Calendar.current.component(.day, from: Date()) / 2) > 0) {
    n = 9
}

if let x = n {
    print(x)
} else {
    print("It's an odd day to get your lucky number.")
}

Forced unwrapping

There are instances when the optional does contain a value, we can access its underlying value by adding an exclamation point (!) to the end of the optional’s name. The exclamation point effectively says, “I know that this optional definitely has a value; please use it.” This is known as forced unwrapping of the optional’s value:

var n: Int? = nil
n = 9
if n != nil {
    print("n has an integer value of \(n!).")
}

Hence, force unwrapping an optional either returns the value if it exists or triggers a runtime error when the optional is nil.

Implicitly unwrapped optionals

An implicitly unwrapped optional is a normal optional behind the scenes, but can also be used like a non-optional value, without the need to unwrap the optional value each time it’s accessed.

We can declare optional variables using exclamation mark instead of a question mark. Such optional variables will unwrap automatically and we do not need to use any further exclamation mark at the end of the variable to get the assigned value.

var greeting: String!
greeting = "Hello, Swift!"

if greeting != nil {
   print(greeting)
} else {
   print("greeting has nil value")
}

An example of using guard to unwrap an optional in Swift

let greeting: String? = "Hello world!"
guard let value = greeting else {
    return
}

print(value)

Optional chaining

The process of querying, calling properties, subscripts and methods on an optional that may be nil is defined as optional chaining. Optional chaining return two values:

  • 1. if the optional contains a value then calling its related property, methods and subscripts returns values .
  • 2. if the optional contains a nil value all its its related property, methods and subscripts returns nil.

Since multiple queries to methods, properties and subscripts are grouped together failure to one chain will affect the entire chain and results in nil value.

Optional chaining as an alternative to forced unwrapping

Optional chaining is specified after the optional value with ? to call a property, method or subscript when the optional value returns some values.

Example for optional chaining with !

class Department {
    var name: String
    
    init(name: String) {
        self.name = name
    }
}

class Employee {
    var id: String
    var name: String
    var department: Department?
    
    init(id: String, name: String, department: String) {
        self.id = id
        self.name = name
        self.department = Department(name: department)
    }
}

let emp = Employee(id: "101", name: "Harish", department: "R&D")
print("Department name is \(emp.department!.name)")

Example for optional chaining with ?

class Department {
    var name: String
    
    init(name: String) {
        self.name = name
    }
}

class Employee {
    var id: String
    var name: String
    var department: Department?
    
    init(id: String, name: String, department: String) {
        self.id = id
        self.name = name
        self.department = Department(name: department)
    }
}

let emp = Employee(id: "101", name: "Harish", department: "R&D")
if let departmentName = emp.department?.name {
   print("Department name is \(departmentName)")
} else {
   print("Department name cannot be retreived")
}

Conclusion

Optionals are in the core of Swift and exist since the first version of Swift. An optional value allows us to write clean code with at the same time taking care of possible nil values.

With Swift’s Optional type and its various features, we can often end up with a very concise code having higher chances of being correct.