Ben Zotto Ben Zotto - 2 months ago 12
Swift Question

Swift optionals and equality operator

Looking for a doc reference or a name or link on this particular behavior, which is similar to optional binding but isn't talked about in that part of the docs.

I can test an optional with the

==
operator, and test against both
nil
and its actual value, without doing any explicit unwrapping:

var toggle: Bool? = nil
if (toggle == true || toggle == nil) {
// do something
}


This compiles and works as you'd want it to, but what's happened here is that I haven't had to unwrap
toggle!
explicitly; the
==
has safely done it for me.

It's convenient but I confess to being a little surprised when I noticed it. Is this just a behavior of the default
==
implementation? Or is something else in the language happening here? Thanks for insight.

Answer

Swift has an equality operator taking two optionals values (of an Equatable base type):

public func ==<T : Equatable>(lhs: T?, rhs: T?) -> Bool

The implementation can be found at Optional.swift:

public func == <T: Equatable>(lhs: T?, rhs: T?) -> Bool {
  switch (lhs, rhs) {
  case let (l?, r?):
    return l == r
  case (nil, nil):
    return true
  default:
    return false
  }
}

and it does what one would expect: The operands are equal if they are both nil, or if they are both not nil and the unwrapped values are equal.

Similar comparison operators < etc taking optionals have been removed in Swift 3, compare SE-0121 Remove Optional Comparison Operators:

Remove the versions of <, <=, >, and >= which accept optional operands.

Variants of == and != which accept optional operands are still useful, and their results unsurprising, so they will remain.

So this works as expected:

let b: Bool? = nil
print(b == true) // prints "false"

But as matt pointed out, this can not be done with implicitly unwrapped optionals, here the left operand will be unwrapped:

let b: Bool! = nil
print(b == true) // crashes