'Enum multiple cases with the same value in Swift

In C you could make your enums have this:

typedef enum _Bar {
    A = 0,
    B = 0,
    C = 1
} Bar;

In Swift I want to make the equivalent. However, the compiler complains that it isn't unique. How do I tell it that I want two cases to have the same value?

enum Bar : Int {
    case A = 0
    case B = 0 // Does not work
    case C = 1
}

I've tried

case A | B = 0

and

case A, B = 0

But it doesn't seem to work as I want it to.



Solution 1:[1]

Here is another way of getting around it:

enum Animal {

  case dog
  case cat
  case mouse
  case zebra

  var description: String {
    switch self {
    case .dog:
      return "dog"

    case .cat:
      return "dog"

    case .mouse:
      return "dog"

    case .zebra:
      return "zebra"

    default:
      break
    }
  }
}

Solution 2:[2]

Swift doesn't allow elements of an enumto share values. From the documentation on enums under the "Raw Values" heading (emphasis mine):

Raw values can be strings, characters, or any of the integer or floating-point number types. Each raw value must be unique within its enumeration declaration.

Solution 3:[3]

I'm not sure you can. The following is taken from Apple.

“Unlike C and Objective-C, Swift enumeration members are not assigned a default integer value when they are created. In the CompassPoints example above, North, South, East and West do not implicitly equal 0, 1, 2 and 3. Instead, the different enumeration members are fully-fledged values in their own right, with an explicitly-defined type of CompassPoint.”

Excerpt from: Apple Inc. “The Swift Programming Language.” iBooks. https://itunes.apple.com/us/book/swift-programming-language/id881256329?mt=11

Since the enumeration members do not implicitly equal 0, 1, etc., the compiler looks at each as a unique value. When you try and duplicate it the compiler complains because it has already been created.

Solution 4:[4]

I encounter the same problem about multiple case with the same value. After googling this problem, I prefer the following solution with computed properties of enum, which come from this post.


Swift enum properties

Solution 5:[5]

You could easily override the == operator to return true every time, except that would be cheating. Let's do this the real way!


I disagree with the accepted answer: Swift does allow raw values to be equivalent, but it does not allow you to write interpretively identical literals. This may cause people to think that what you are asking is impossible. But, your question is answerable, and we will have to work around Swift's lexical grammar a little bit.

i.e. 1.0 and 1.000 are interpretively identical Double literals, since the extra zeroes collapse.

The simplest proof of this is to take advantage over floating point type underflow/overflow. The literals themselves are not identical, but the values themselves are the same.

enum ExhibitA: Double {
    case a = 0.0
    case b = 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
}
print(ExhibitA.a == ExhibitA.b) // true
print(ExhibitA.a.rawValue) // 0.0
print(ExhibitA.b.rawValue) // 0.0

So I technically answered your question, but this has no practical value. Let's try and make it work for all numbers, as well as include more types.


If you let your enum cases be JSON decodable String raw values, and apply the ExpressibleByStringLiteral protocol to convert them into their specified type, you can do just that.

import Foundation

struct EnumWrapper<T: Codable & Equatable>: ExpressibleByStringLiteral, Equatable {
    var value: T
    init(_ t: T) { value = t }
    init(stringLiteral value: StringLiteralType) {
        try! self.init(JSONDecoder().decode(T.self, from: Data(value.utf8)))
    }
}


enum Foo: EnumWrapper<Int> {
    case a = "1"
    case b = "1 "
}
print(Foo.a == Foo.b) // true
print(Foo.a.rawValue.value) // 1
print(Foo.b.rawValue.value) // 1

Awesome! Now you can use as a raw value anything that conforms to Decodable.
i.e. a 4D Array of Booleans:

enum Example: EnumWrapper<[[[[Bool]]]]> {
    case woah = "[[[[true, false, true], [false], []], []]]"
}
print(Example.woah.rawValue.value) // [[[[true, false, true], [false], []], []]]

This pattern is dangerous when applied to Sets or Dictionaries. Half the time you run the code below, you will receive a run-time error saying the dictionary has duplicate keys.

let foo : [Foo : Bool] = [
    .a : true,
    .b : false
]

Solution 6:[6]

I found this by sheer coincidence and was surprised there's no Swift-y dark magic in any of the answers (which are still good, of course). Personally I don't like the static properties as much because they introduce overhead elsewhere, e.g. in the pattern matching.

I think the "cleanest" solution would be to rely on RawRepresentable and define that yourself. Then you can counter the main reason why Swift doesn't support this out of the box: the init?(rawValue:) method. By just specifying String as the adopted raw value (i.e. enum MyEnum: String { ... }) the compiler can't generate the logic for that on its own. It would need to know which case to skip, as there are not "enough" potential raw values defined (since one or more are doubled). Adopting the protocol yourself allows you to simply chose one case as the "default" for a given raw value string and basically prevent the other one from constructed with a raw value (regular construction still works, of course).

Unfortunately that is also a bit of overhead, as the former case myCase = "its_raw_value" then gets distributed over

  • the regular case (without the raw value String): case myCase (the definition)
  • a switch in the init?(rawValue:) method: ... case "its_raw_value": return .myCase ...
  • a switch in the required rawValue property: ... case .myCase: return "its_raw_value" ...

I think I have a nice way to reduce that a little and keep the raw values from floating around too much. I wrote a playground to illustrate and will simply paste it here:


// define protocol and a default implementation
protocol SloppyRawRepresentable
where Self: RawRepresentable, Self.RawValue: Hashable, Self: CaseIterable {
}
extension SloppyRawRepresentable {
    init?(rawValue: RawValue) {
        var tempMapping = [RawValue: Self]()
        for oneCase in Self.allCases {
            // first come first served. any case after the first having the same
            // raw value is simply ignored, so the first is the "default"
            if tempMapping[oneCase.rawValue] == nil {
                tempMapping[oneCase.rawValue] = oneCase
            }
        }
        guard let candidate = tempMapping[rawValue] else { return nil }
        self = candidate
    }
}

// use it. Note we don't need the init
enum EventNames: SloppyRawRepresentable {
    typealias RawValue = String

    var rawValue: String {
        switch self {
        case .standardEvent: return "standard"
        case .joesConfig: return "iAmJoe"
        case .myConfig: return "iAmJoe"
        }
    }

    case standardEvent
    case joesConfig
    case myConfig
}

// some example output

print(EventNames.standardEvent)
print(EventNames.joesConfig)
print(EventNames.myConfig)

print(EventNames.standardEvent.rawValue)
print(EventNames.joesConfig.rawValue)
print(EventNames.myConfig.rawValue)

print(EventNames(rawValue: "standard")!)
print(EventNames(rawValue: "iAmJoe")!)
print(EventNames(rawValue: "iAmJoe")!)

print(EventNames(rawValue: "standard")!.rawValue)
print(EventNames(rawValue: "iAmJoe")!.rawValue)
print(EventNames(rawValue: "iAmJoe")!.rawValue)

It should be self-explanatory. The case definition and assigning it its raw value is still split, I don't think there's a way around that, but it can come in handy. Of course all this requires the RawValue be constraint and I rely on the enum be CaseIterable to easily construct that helper dictionary, but I think that should be okay, performance wise.

Solution 7:[7]

Disclaimer: I'm not recommending this. Most people would not consider best practice. There are downsides, depending on the application. Let's just say these ideas are theoretical, hypothetical, impure, just presented for contemplation

One possibility is to add some sort of meaningless differentiator sufficient to thwart Swift's check for identity that doesn't affect what you are doing with the raw values in your code.

He's an example with a Float, where, in music, A? (A sharp) is the same frequency as B? (B flat). They are both different annotations for the same thing, in other words.

Differences measured in microHz are meaningless to audio engines, yet sufficient to differentiate case values in a Swift enumeration. In other words, practically speaking, there is no difference between 116.540 and 116.540001 in most music applications:

enum NoteFrequency : Float = {
   case A = 110.0, A_SHARP = 116.540, B_FLAT = 116.540001
}

Going from quasi-tolerable to uglier: For strings that only get assigned and printed you might add a non-printable character to differentiate.

Obviously this has downsides (potentially serious), if you do something like this and later you (or someone else) might be unaware of what you did, and writes code that doesn't account for it (such as using in rawValue of an enumeration in String comparisons) and their code fails. To make this work in String comparisons you'd have to probably do something to ignore the last character or lop it the unprintable character with myEnumString.rawValue.dropLast() before comparing...

 enum Animals : String = {
     case CAT = "Feline\u{01}", LION = "Feline\u{02}"
 }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 cohen72
Solution 2 strange quark
Solution 3 Peter Mortensen
Solution 4 Peter Mortensen
Solution 5
Solution 6 Gero
Solution 7 clearlight