Do you need help on a specific subject? Use the contact form (Request a blog entry) on the right hand side.

2015-05-25

Swift "Enum Compare" Design Pattern

Comparing enum's in Swift is easy... if the enum does not have associated values. As in the following two examples:

Example 1

enum Enum1: Int {
    case ONE = 1
    case TWO = 2
}

let a1 = Enum1.ONE
let b1 = Enum1.TWO

if a1 == b1 {
    println("Equal")
} else {
    println("Not equal")
}

Example 2

enum Enum2 {
    case ONE
    case TWO
}

let a2 = Enum2.ONE
let b2 = Enum2.TWO

if a2 == b2 {
    println("Equal")
} else {
    println("Not equal")
}

But if the enum has an associated value things get more difficult:

Example 3

enum Enum3 {
    case ONE
    case TWO(String)
}

let a3 = Enum3.ONE
let b3 = Enum3.TWO("wow")

if a3 == b3 {
    println("Equal")
} else {
    println("Not equal")
}

Will cause the following error: Binary operator '==' cannot be applied to two Enum3 operands

So how can we compare enums with an associated value?
The following pattern does that. I am not claiming that it is the only way, but so far its the best I can come up with. If you have something better, please let us know.

If we add the following function to the Enum3 example, everything compiles fine:
(Thanks to ibex10 for pointing out an error in the original pattern, this has now been fixed)

func == (left: Enum3, right: Enum3) -> Bool {
    
    switch left {
        
    case .ONE:
        
        switch right {
        case .ONE: return true
        default: return false
        }
        
    case let .TWO(str1):
        
        switch right {
        case let .TWO(str2) : return (str1 == str2)
        default: return false // Cover all cases
        }
    }

}

As you can see, for the associated values we need to hand craft the comparison.

Happy coding...

Did this help?, then please help out a small independent.
If you decide that you want to make a small donation, you can do so by clicking this
link: a cup of coffee ($2) or use the popup on the right hand side for different amounts.
Payments will be processed by PayPal, receiver will be sales at balancingrock dot nl
Bitcoins will be gladly accepted at: 1GacSREBxPy1yskLMc9de2nofNv2SNdwqH

We don't get the world we wish for... we get the world we pay for.

5 comments:

  1. Good try but what happens with the following case?

    let u = Enum3.ONE
    let v = Enum3.ONE

    if u == v {
    print("Equal")
    } else {
    print("Not equal")
    }

    Infinite recursion.

    ReplyDelete
    Replies
    1. Good catch!
      Yes, we need to use switch within switch for all cases.
      I have updated the pattern so that this is now part of the post.
      Thank you very much!

      Delete
  2. Here's a more compact way to define == for enumerations with associated values:

    func == (left: Enum3, right: Enum3) -> Bool {
    switch (left, right) {
    case (.ONE, .ONE):
    return true
    case (.TWO(let str1), .TWO(let str2)):
    return str1 == str2
    default:
    return false
    }
    }

    ReplyDelete