# Comparing enum cases while ignoring associated values

**URL:** <https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922>\
**Category:** Using Swift\
**Created:** [September 6, 2018, 9:06pm UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922 "2018-09-06T21:06:32Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![sjavora](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/sjavora/32/9323_2.png) [@sjavora](https://forums.swift.org/u/sjavora)\
**Post date:** [September 6, 2018, 9:06pm UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922/1 "2018-09-06T21:06:32Z")

</div>

Multiple times I have now wanted to compare two values of an enum while ignoring their respective associated values.

```swift
enum Foo {
    case string(String)
    case number(Int)
}

let a = Foo.string("str")

a == Foo.string // Binary operator '==' cannot be applied to operands of type 'Foo' and '(String) -> Foo'

```

I understand why this doesn't work, but... I really want it to! Looking around the web for workarounds has led me to [Erica Sadun's article](https://ericasadun.com/2017/01/31/challenge-filtering-associated-value-enumeration-arrays/), an interesting [gist](https://gist.github.com/bradhilton/c58ec6c2d1a68b6de3261322e994aab0) from the comments of said article, and even a [post from Swift 1.2 era](https://stackoverflow.com/q/31548855) asking basically the same question.

All the solutions I've seen so far either require me to manually write type-specific code, or are plain ugly. Even if there are workarounds, though, I'd love for the following to work as well:

```swift
foos.contains(.number)

```

...which could only work if the cases _without their associated values_ were somehow `Equatable`.

I suppose I'm posting this here out of frustration and hoping that perhaps someone from the Swift team will chime in, because this feels like it should work and just doesn't...

---

<div class="post-metadata">

**Author:** ![Naxum](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/naxum/32/3174_2.png) [@Naxum](https://forums.swift.org/u/Naxum)\
**Post date:** [September 6, 2018, 10:11pm UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922/2 "2018-09-06T22:11:13Z")

</div>

My only use of Sourcery is to auto-generate a subtype on my associated value enums so I can do simple `==` and `!=` checks for their case names. I would love to see this feature exist in Swift.

It should be easy to do things like the following without resorting to weird quirks or a bunch of extra code

```swift
enum State {
  case ready
  case loading(reasons: [String])
}

let stateA = State.ready
let stateB = State.loading(reasons: ["ReasonA", "ReasonB"])

print(stateA.case == stateB.case) //false

if stateA.case != .loading { 
  // do something
}
```

There are a bunch of hiccups when writing `if case let something = .enumCase` (including the inability to use `!=` with `case let`).  
I too would love to see it simplified!

---

<div class="post-metadata">

**Author:** ![mpangburn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mpangburn/32/45144_2.png) [@mpangburn](https://forums.swift.org/u/mpangburn)\
**Post date:** [September 6, 2018, 10:37pm UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922/3 "2018-09-06T22:37:38Z")

</div>

Relevant discussion regarding enum ergonomics: [Automatically derive properties for enum cases - #5 by stephencelis](https://forums.swift.org/t/automatically-derive-properties-for-enum-cases/10843/5)

---

<div class="post-metadata">

**Author:** ![lancep](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/lancep/32/1509_2.png) [@lancep](https://forums.swift.org/u/lancep)\
**Post date:** [September 6, 2018, 10:50pm UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922/4 "2018-09-06T22:50:36Z")

</div>

You can always do

```swift
if case .string = a { 
  print("found a string!") 
}

```

---

<div class="post-metadata">

**Author:** ![Dante-Broggi](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dante-broggi/32/7955_2.png) [@Dante-Broggi](https://forums.swift.org/u/Dante-Broggi)\
**Post date:** [September 7, 2018, 12:21am UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922/5 "2018-09-07T00:21:14Z")

</div>

I think that, similar to [SE-0194](https://github.com/apple/swift-evolution/blob/master/proposals/0194-derived-collection-of-enum-cases.md), the best way to provide this feature would be to add a `CaseDiscriminatable` (to be bike-shedded) protocol, for which, like `CaseEnumerable` a compiler-provided default implementation would be created for same-file extensions.

e.g:

```swift
protocol CaseDiscriminatable {
  associatedtype Discriminator: Hashable
  var case: Discriminator
}

```

---

<div class="post-metadata">

**Author:** ![Tchelyzt](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tchelyzt/32/19919_2.png) [@Tchelyzt](https://forums.swift.org/u/Tchelyzt)\
**Post date:** [October 6, 2021, 10:34am UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922/6 "2021-10-06T10:34:51Z")

</div>

Here's a simple (if slightly verbose) way to do it:

```swift
enum Foo {
    case string(String)
    case number(Int)

   func hasSameCaseAs(_ type: Self) -> Bool {
      switch self {
         case .string: if case .string = type { return true }
         case .number: if case .number = type { return true }
      }
      return false
   }
}

var a = Foo.string("hello")
var b = Foo.number(6)
var c = Foo.number(5)

a.hasSameCaseAs(b) // returns false
b.hasSameCaseAs(c) // returns true
a.hasSameCaseAs(Foo.string("")) // returns true

```

Doesn't use the == operator but it's not really ==, is it?  
As an aside, I'm unhappy with the form: `if case .string = type { return true }` too since its not an assignment but a comparison and would be better served by ==.

---

<div class="post-metadata">

**Author:** ![tclementdev](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tclementdev/32/13398_2.png) [@tclementdev](https://forums.swift.org/u/tclementdev)\
**Post date:** [October 6, 2021, 11:46am UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922/7 "2021-10-06T11:46:35Z")

</div>

If the enum is Equatable, this first test works but the second doesn't, maybe it should?

```
a == .string("hello") // true
a == .string(_) // error: '_' can only appear in a pattern or on the left side of an assignment

```

To me `if a == .string(_)` looks so much better than `if case .string(_) = a`.

---

<div class="post-metadata">

**Author:** ![Dmitriy\_Ignatyev](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dmitriy_ignatyev/32/11340_2.png) [@Dmitriy\_Ignatyev](https://forums.swift.org/u/Dmitriy_Ignatyev)\
**Post date:** [October 6, 2021, 2:48pm UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922/8 "2021-10-06T14:48:02Z")

</div>

Hello. This topic is regularly being discussed. Some of the discussions:

> [@Pitch: Auto-synthesize cases for enums](https://forums.swift.org/t/pitch-auto-synthesize-cases-for-enums/10075):
>
> To go along with the recently reviewed [Derived Collection of Enum Cases](https://github.com/apple/swift-evolution/blob/master/proposals/0194-derived-collection-of-enum-cases.md), I'd like to propose that we also derive a Case enum for all enums. The problem One of the biggest issues I have with using enums is that comparing the case of two enums is really painful. Take for example, if I decided to make a game called Orc vs Elves vs Humans, and decided to represent them as an enum enum Race { case orc(weapon: Weapon) case elf(spell: MagicSpell) case human(karateMove: KarateMove) func atta…

> [@DiscriminatedUnion Protocol](https://forums.swift.org/t/discriminatedunion-protocol/28094):
>
> I've had this idea for a while but have been distracted by a great many things. My hand has been forced, a little, by [Extract Payload for enum cases having associated value - #140 by gwendal.roue](https://forums.swift.org/t/extract-payload-for-enum-cases-having-associated-value/27606/140). I consider this a possible alternative. I admit that I've stopped following the thread consistently but I've checked in on the thread every now and then. Motivation There are times when you need to construct a decision tree about and enum well before you have an instance of that enum. Consider a stat…

As current workaround, you can use this solution:

> [@Getting the name of a Swift enum value](https://forums.swift.org/t/getting-the-name-of-a-swift-enum-value/35654/17):
>
> I don't like to advertise, but a user of a library I'm working on had this exact issue. While I agree that the standard library could probably vend it's own way to give this information to users, I have an interim solution here: [Accessing name of enum with a raw value · Issue #9 · Azoy/Echo · GitHub](https://github.com/Azoy/Echo/issues/9#issuecomment-624903603). (I believe everything in this solution is ABI stable on Darwin platforms.) This just looks at the enum metadata to get it's name.

But be careful and keep in mind, it is not safe and can be broken in future.

---

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [October 6, 2021, 7:49pm UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922/9 "2021-10-06T19:49:36Z")

</div>

> [@tclementdev](#):
>
> To me `if a == .string(_)` looks so much better than `if case .string(_) = a` .

this works now without brackets and Equatable requirement:

```
if case .string = a {

```

if to choose between:

```
if a == .string { // proposed
if .string == a { // same
vs
if case .string = a { // existing

```

then +1 for the former form. interestingly Equatable requirement can be optional:

```
enum E {
    case string(String)
    case red
    case green
    case blue
}
if a == .string { // proposed: ok
if .string == a { // same
if a == .string("hello") { // error, 'Equatable' required
if a == .red { // error, 'Equatable' required

```

---

<div class="post-metadata">

**Author:** ![nicodioso](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/nicodioso/32/30863_2.png) [@nicodioso](https://forums.swift.org/u/nicodioso)\
**Post date:** [July 21, 2023, 5:58am UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922/10 "2023-07-21T05:58:49Z")

</div>

You can create a variable that holds their case names then compare it with each other.

```swift
enum Foo {
    case string(String)
    case number(Int)

    private var caseName: String {
        switch self {
            case .number: return "number"
            case .string: return "string"
        }
    }

    func hasSameCase(as type: Self) -> Bool {
        return self.caseName == type.caseName
    }
}

```

I think it's easier than using `switch self` then checking the equality one by one each case

---

<div class="post-metadata">

**Author:** ![Joe\_Groff](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/joe_groff/32/1929_2.png) [@Joe\_Groff](https://forums.swift.org/u/Joe_Groff)\
**Post date:** [July 21, 2023, 4:28pm UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922/11 "2023-07-21T16:28:58Z")

</div>

This might be an interesting use case for a macro, which could generate a nested `Cases` enum with one `case` for each case in the outer enum but without the payloads, along with a computed property that maps the payload cases in the outer enums to the corresponding no-payload cases in the inner enum.

---

<div class="post-metadata">

**Author:** ![mcritz](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/mcritz/32/7094_2.png) [@mcritz](https://forums.swift.org/u/mcritz)\
**Post date:** [July 17, 2024, 1:59pm UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922/12 "2024-07-17T13:59:55Z")

</div>

@nicodioso Thank you so much for this. Someone should pitch this as a language feature so it isn’t buried or hand-rolled.

```swift
Button {...}
.disabled(status.isNot(.pending(reason: ""))

```

is very helpful! If I could add a feature to Swift, it would be something like...

```swift
Button {...}
.disabled(status.isNot(.pending))

```

so we could ignore associated values on enums for the purposes of “simple” comparison.

---

<div class="post-metadata">

**Author:** ![bdkjones](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/bdkjones/32/13872_2.png) [@bdkjones](https://forums.swift.org/u/bdkjones)\
**Post date:** [April 13, 2025, 5:13am UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922/13 "2025-04-13T05:13:34Z")

</div>

Testing the case of an enum while discarding the associated value is definitely a Swift pain point that stands out more and more as apps transition to SwiftUI.

SwiftUI can't work with protocols, so to display a typical hierarchical OutlineView that has different model objects at each level, I wrap those in an enum:

```swift
enum NavNode
{
    case client(Client)
    case project(Project)
    case job(Job)
    case version(Version)
}

```

Some UI elements, such as context menu items, need to be enabled/disabled based on which type of object is selected in this tree. But in the `.disabled()` view modifier, `if case let` and `switch` are out. I need to express, "I don't care what the associated value is; just tell me if this thing is a `.client`, `.project`, `.job`, or `.version`."

I currently do that the same way people are doing it here, but it's definitely something that should just _be_ in the language.

---

<div class="post-metadata">

**Author:** ![stephencelis](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/stephencelis/32/2675_2.png) [@stephencelis](https://forums.swift.org/u/stephencelis)\
**Post date:** [April 13, 2025, 5:34am UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922/14 "2025-04-13T05:34:01Z")

</div>

[Case Paths](https://github.com/pointfreeco/swift-case-paths) is a well-explored library supporting this and more, and I'd be happy to see its features supported directly in the language, but sadly it hasn't been prioritized by anyone with the compiler knowhow just yet.

---

<div class="post-metadata">

**Author:** ![bdkjones](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/bdkjones/32/13872_2.png) [@bdkjones](https://forums.swift.org/u/bdkjones)\
**Post date:** [April 13, 2025, 5:45am UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922/15 "2025-04-13T05:45:20Z")

</div>

I'm sure there's 742 edge cases I don't know about, but it always seemed to me like this is the most elegant syntax:

```swift
let myProject = Project()
let foo: NavNode = .project(myProject)

if foo == .client(_) {
   print("We have a client case")
}

```

And that would translate well to SwiftUI:

```swift
Button("Blah") {
}
.disabled(selectedNavNode != .project(_))

```

It'd be even nicer if they just worked without the underscore at all, but that seemed like asking too much. Maybe if you decorate the enum with the equivalent of `@discardableResult`? Something like:

```swift
@discardableValue enum NavNode
{
...
}

// Now the concern about obfuscating the fact that this enum has associated values is gone because we've explicitly opted in:
@State var selectedNavNode: NavNode?

Button("Blah") {
}
.disabled(selectedNavNode != .project)

```

---

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [April 13, 2025, 6:44am UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922/16 "2025-04-13T06:44:19Z")

</div>

> [@bdkjones](#):
>
> ```swift
> if foo == .client {
> print("We have a client case with no underscores.")
> }
> 
> ```

The use cases that use if/switch to compare to another "constant" value is not a good motivator, as you could write this today:

```swift
if case .client = foo {
}

```

It becomes more interesting when you need comparing two non-constant values.

* * *

This works in basic cases:

```swift
func valueBaseName(_ value: Any) -> String {
    var string = "\(value)" // string("hello")
    if let paren = string.range(of: "(") {
        string .removeSubrange(paren.lowerBound...)
        return string
    } else {
        return string
    }
}

print(valueBaseName(Foo.string("hello"))) // "string"
print(valueBaseName(Foo.number(42))) // "number"
// used like:
valueBaseName(foo) == valueBaseName(bar)

```

Although it's easy to break it (e.g. by having a CustomStringConvertible implementation that does something else).

* * *

+1 to having something better built-in, ideally that's O(1) in both time and code size.

---

<div class="post-metadata">

**Author:** ![bdkjones](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/bdkjones/32/13872_2.png) [@bdkjones](https://forums.swift.org/u/bdkjones)\
**Post date:** [April 13, 2025, 6:57am UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922/17 "2025-04-13T06:57:07Z")

</div>

> [@tera](#):
>
> The use cases that use if/switch to compare to another "constant" value is not a good motivator, as you could write this today:
> 
> ```swift
> if case .client = foo {
> }
> 
> ```

That is not an option in `.disabled()`. If you're lucky, the compiler will tell you `'if' may only be used as expression in return, throw, or as the source of an assignment`. If you're unlucky, it will tell you it can't type check your view in reasonable time.

My primary need for this is in SwiftUI. If I'm not working in a ViewModifier, I generally _do_ care about the associated value and `switch` or `if case let` work fine.

I've updated my examples above to stick to SwiftUI viewModifiers, since that's where the pain point really is.

---

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [April 13, 2025, 7:01am UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922/18 "2025-04-13T07:01:54Z")

</div>

Got you. That would be less of a problem once we finally implement "Full Expressions" form of [SE-0380](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0380-if-switch-expressions.md#full-expressions).

* * *

Quite awkward workaround:

```swift
Button("Blah") {
}
.disabled({if case .project = selectedNavNode { true } else { false }}())

```

would be a bit nicer with "full expressions" implemented:

```swift
Button("Blah") {
}
.disabled(if case .project = selectedNavNode { true } else { false })

```

although still looks heavy and redundant.

---

<div class="post-metadata">

**Author:** ![bdkjones](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/bdkjones/32/13872_2.png) [@bdkjones](https://forums.swift.org/u/bdkjones)\
**Post date:** [April 13, 2025, 7:20am UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922/19 "2025-04-13T07:20:26Z")

</div>

> [@tera](#):
>
> Quite awkward workaround:
> 
> ```swift
> Button("Blah") {
> }
> .disabled({if case .project = selectedNavNode {true} else {false}}())
> 
> ```

Ha, stack a few of those in a modifier and you're basically writing Lisp.

---

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [April 13, 2025, 7:51am UTC](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922/20 "2025-04-13T07:51:17Z")

</div>

> [@bdkjones](#):
>
> ```swift
> Button("Blah") {
> }
> .disabled(selectedNavNode != .project)
> 
> ```

How about this (new) syntax?

```swift
.disabled(case selectedNavNode != case .project)

```

Could be useful in the other mentioned use case of comparing two variables:

```swift
case foo == case bar

```

The enum itself will not have to be Equatable for this to work.

`case foo` or `case .project` would give a discriminator, e.g. Int.

```swift
enum NavNode {
    case client(Client)
    case project(Project)
    case job(Job)
    case version(Version)
}

print(case NavNode.project) // 1
let v = NavNode.project(Project(...))
print(case v) // 1

```

[Next page](https://forums.swift.org/t/comparing-enum-cases-while-ignoring-associated-values/15922.md?page=2)
