Ben Zotto Ben Zotto - 11 months ago 49
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
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
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 Source

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
    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