3

Swift: Comparing Enums With Associated Values

 3 years ago
source link: http://www.thomashanning.com/swift-comparing-enums-with-associated-values/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Comparing enums in Swift is very straightforward – as long as they don’t have associated values. In this post we will discuss, what you can do in that case.

Hint: This post is using Swift 4

Content

Video

Comparing Enums Without Associated Values

Let’s start with the simple case:

enum TestEnum {
    case testA
    case testB
let testEnum1 = TestEnum.testA
let testEnum2 = TestEnum.testB
let testEnum3 = TestEnum.testA
print(testEnum1 == testEnum2) //false
print(testEnum1 == testEnum3) //true

So in this example we are defining an enum called TestEnum, that has two cases. Then we are declaring two variables of this type and we compare them – they behave as expected and everything is working fine.

Comparing Enums With Associated Values

Now let’s look into the hard stuff. First, we add an associated value to one of the cases:

enum TestEnum {
    case testA(Int)
    case testB
let testEnum1 = TestEnum.testA(5)

As already explained in this post, you can use an enum with associated values to add some additional information. It can only be accessed within a switch statement though:

enum TestEnum {
    case testA(Int)
    case testB
let testEnum1 = TestEnum.testA(5)
switch testEnum1 {
case .testA(let a):
    print("Case testA with associated value \(a)")
case .testB:
    print("Case testB")

As expected, the output is

Case testA with associated value 5

So, now let’s try to compare two of them:

enum TestEnum {
    case testA(Int)
    case testB
let testEnum1 = TestEnum.testA(5)
let testEnum2 = TestEnum.testB
if testEnum1 == testEnum2 {   //COMPILER ERROR!!!
    print("equal")

In this case, we get an compiler error:

Binary operator '==' cannot be applied to two 'TestEnum' operands

And this makes perfectly sense because it’s not clear when they are equal. For example, are two testA values equal if their associated values are equal? Or are two testA values always equal? It depends on the circumstances, on the meaning of the enum.

But we can actually implement our own implementation of ==. For that, we implement the Equatable protocol:

enum TestEnum {
    case testA(Int)
    case testB
extension TestEnum: Equatable {
    public static func ==(lhs: TestEnum, rhs:TestEnum) -> Bool {
        switch lhs {
        case .testA(let a):
            switch rhs {
            case .testA(let b):
                return a == b
            case .testB:
                return false
        case .testB:
            switch rhs {
            case .testB:
                return true
            case .testA:
                return false

That’s a lot of code for a little bit of work, but it does the job! Now, two TestEnum are equal, if one of the following two conditions is true:

  • Both are testB cases.
  • Both are testA cases AND their associated values are equal.

Of course it’s possible to write that code a little bit more elegant:

enum TestEnum {
    case testA(Int)
    case testB
extension TestEnum: Equatable {
    public static func ==(lhs: TestEnum, rhs:TestEnum) -> Bool {
        switch (lhs,rhs) {
        case (.testB, .testB):
            return true
        case (.testA(let a), .testA(let b)):
            return a == b
        default:
            return false

And now let’s test whether it’s working as expected:

let testEnum1 = TestEnum.testA(5)
let testEnum2 = TestEnum.testA(10)
let testEnum3 = TestEnum.testA(5)
let testEnum4 = TestEnum.testB
let testEnum5 = TestEnum.testB
print(testEnum1 == testEnum2) //false
print(testEnum1 == testEnum3) //true
print(testEnum1 == testEnum4) //false
print(testEnum4 == testEnum5) //true

Obviously, it can also be implemented in another way, like this:

  • Both are testB cases.
  • Both are testA cases

Then, the associated values don’t have an influence on the equality:

extension TestEnum: Equatable {
    public static func ==(lhs: TestEnum, rhs:TestEnum) -> Bool {
        switch (lhs,rhs) {
        case (.testB, .testB):
            return true
        case (.testA,.testA):
            return true
        default:
            return false
let testEnum1 = TestEnum.testA(5)
let testEnum2 = TestEnum.testA(10)
let testEnum3 = TestEnum.testA(5)
let testEnum4 = TestEnum.testB
let testEnum5 = TestEnum.testB
print(testEnum1 == testEnum2)
print(testEnum1 == testEnum3)
print(testEnum1 == testEnum4)
print(testEnum4 == testEnum5)

As said before, it depends on the context.

Title Image: @ arda savasciogullari / shutterstock.com


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK