Swift
enum
associated values
compare enums
programming tips

How to compare Swift enum with associated values by ignoring its associated value?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Swift can compare enum values with == only when the entire value matches, including any associated payload. If you want to compare just the case and ignore the associated value, the right approach is usually pattern matching or a separate case-only representation.

Why Direct Equality Is Not Enough

Consider an enum like this:

swift
1enum NetworkState {
2    case idle
3    case loading(taskID: Int)
4    case failed(message: String)
5}

These two values are not equal:

swift
let a = NetworkState.loading(taskID: 1)
let b = NetworkState.loading(taskID: 99)

That is correct behavior. They are the same case, but not the same full value.

If your logic only cares that both values are .loading, you need a different kind of comparison.

Use Pattern Matching For One-Off Checks

For simple checks, if case or switch is the most direct solution.

swift
1let state = NetworkState.loading(taskID: 42)
2
3if case .loading = state {
4    print("The request is loading")
5}

This ignores the associated value entirely.

You can also compare two values by matching both against the same case:

swift
1func sameCase(_ lhs: NetworkState, _ rhs: NetworkState) -> Bool {
2    switch (lhs, rhs) {
3    case (.idle, .idle),
4         (.loading, .loading),
5         (.failed, .failed):
6        return true
7    default:
8        return false
9    }
10}
11
12print(sameCase(.loading(taskID: 1), .loading(taskID: 999))) // true
13print(sameCase(.idle, .failed(message: "Oops")))            // false

That is explicit, readable, and often enough for small enums.

Create A Case-Only Projection

If you need this comparison in many places, a cleaner design is to expose a case-only property.

swift
1enum NetworkState {
2    case idle
3    case loading(taskID: Int)
4    case failed(message: String)
5
6    enum Kind {
7        case idle
8        case loading
9        case failed
10    }
11
12    var kind: Kind {
13        switch self {
14        case .idle:
15            return .idle
16        case .loading:
17            return .loading
18        case .failed:
19            return .failed
20        }
21    }
22}
23
24let first = NetworkState.loading(taskID: 1)
25let second = NetworkState.loading(taskID: 55)
26
27print(first.kind == second.kind) // true

This technique scales well because it separates two different questions:

  • Are these the same full enum value
  • Are these the same case regardless of payload

Once you make that distinction explicit, the rest of the code becomes much easier to read.

Add A Helper Method For Readability

Another option is to wrap the comparison in a method:

swift
1extension NetworkState {
2    func hasSameCase(as other: NetworkState) -> Bool {
3        switch (self, other) {
4        case (.idle, .idle),
5             (.loading, .loading),
6             (.failed, .failed):
7            return true
8        default:
9            return false
10        }
11    }
12}
13
14print(NetworkState.failed(message: "A").hasSameCase(as: .failed(message: "B")))

This keeps call sites readable without forcing every caller to write a switch.

What About Equatable

You can still make the enum conform to Equatable, but that does not solve the "ignore associated value" requirement by itself. Normal Equatable should usually keep its standard meaning and compare the entire value.

If you overload equality to ignore payloads, you create surprising behavior:

  • two .loading states with different task identifiers become "equal"
  • stored collections and tests may behave unexpectedly
  • the enum no longer models full value identity correctly

That is why a separate helper or kind property is usually better than redefining equality semantics.

Choose The Right Pattern

Use pattern matching when:

  • you only need a local check
  • the enum has few cases
  • readability is more important than reuse

Use a kind property when:

  • many parts of the code need case-only comparison
  • the enum has associated values on several cases
  • you want a reusable case identity

Use a helper method when:

  • you want concise call sites
  • you do not want to expose another nested enum

All three are valid. The difference is mostly about reuse and clarity.

Common Pitfalls

The biggest mistake is trying to compare only the case with normal == and then being surprised that associated values are included. That is how Swift value equality is supposed to work.

Another mistake is redefining Equatable to ignore associated values globally. It solves one short-term need but makes the enum semantically misleading everywhere else.

People also sometimes duplicate pattern-matching logic all over the codebase. Once the enum is used broadly, a kind property or helper method is usually worth the small upfront cost.

Finally, if the payload matters in some places and not others, keep those two ideas separate in the API. That distinction prevents subtle bugs.

Summary

  • Normal equality compares both the enum case and its associated value.
  • Use if case or switch when you only need a local case-only check.
  • A nested Kind enum plus a computed property is a clean reusable design.
  • Helper methods such as hasSameCase(as:) keep call sites readable.
  • Avoid redefining Equatable to ignore associated values unless that is truly the model's full semantics.

Course illustration
Course illustration

All Rights Reserved.