Swift: Equatable with Optionals

@andrewcbancroft recently wrote a great article about how Every Swift Value Type Should Be Equatable – go ahead and read it, I’ll wait…

One thing that stood out as missing from this article was comparing different sets of optional values. In the past, I have implemented the following equality for values to make sure optionals were covered:

I mentioned this in my Swift Newsletter this week, only to get the following responses on Twitter:

Of course, I had to see it for myself, so I tried this in the playground:

Turns out, the Equatable implementation for optionals is not necessary. It just works!

Enjoy the article? Join over 14,500+ Swift developers and enthusiasts who get my weekly updates.

  • Andrew Bancroft

    Awesome! When I saw the conversation, I thought, “Oh know! I’ve left out something important!” Thanks for trying it out and verifying that the expectations when comparing Optionals are met, even without implementing the additional operators.

    And as always, I appreciate you including my article in this week’s newsletter!

  • Kevin DeLeon

    Nice to know!

  • Vjosullivan

    The single non-optional == definition works for me even when either or both sides are optional, too. That’s using Swift 2.0. I haven’t tried it for earlier versions.

  • A.C Che

    It is a well-hidden trap in optionals.

  • Rikki Gibson

    To be honest, it would be pretty lousy to require us to implement our own equality comparison where one side or the other is optional. If one value isn’t optional or is a .Some and the other value is a .None you know they’re not equal. If they’re both .Some then you use the comparer defined for the values inside the optionals. If they’re both .None you know they’re equal.

    • I think you need to you use the generics type, since it accepts any type, but still you will need to put your own validation.

      In Playground:

      func == (lhs: T, rhs: T) -> Bool {
      let result = lhs == rhs
      return result

      let arr: [String] = [“1”, “2”, “3”, “3”]
      let arr2: [String] = [“1”, “2”, “3”, “3”]
      let arr3: [String] = []

      arr == arr2 // true
      arr == arr3 // false

  • Abizer Nasir

    Probably pedantic, but I couldn’t let it pass:

    You’ve defined an initialiser for the struct, which is not needed in this case. Structs give you default initialisers with named values automatically, and if you define any of the fields with default values, then you get an empty initialiser Place() for free as well – although in this case it isn’t valid as a Place should be fully defined.

    Delete your init(...) func, and you’ll see that it still “just works”

    • Haha, good point! Copied the code from Andrew’s blog post – should have taken a better look at it. Will update!

  • I have tried it and analysed, its more reliable and sophisticated declaring them with optionals. The reason is you won’t need to declare more than one ‘==’ func and is safe. You could pass and compare two optional ‘TestModel’, two non-optional ‘TestModel’ or an optional ‘TestModel’ and a non-optional ‘TestModel’ or even nil

    In Playground:

    class TestModel {
    var testName: String?

    init(testName: String) {
    self.testName = testName

    func == (lhs: TestModel?, rhs: TestModel?) -> Bool {
    let result = lhs?.testName == rhs?.testName
    return result

    let fString: TestModel? = TestModel(testName: “1234”)
    let fString2: TestModel = TestModel(testName: “1234”)
    let fString3: TestModel? = nil
    let fString4: TestModel? = nil

    fString == fString2 // true
    fString == fString3 // false
    fString2 == fString3 // false
    fString3 == fString4 // true

  • Matthew Purland

    This isn’t necessarily the case for Swift classes that extend NSObject. You must implement == for that type to handle lhs/rhs optional values.


    This is in total agreement with @nferocious76.