[Pitch] Synthesize a Discriminator enum for any frozen enum with one or more associated values

I have lost track of the number of times I've had to write the following code:

enum Foo {
    case weGot(Int)
    case someCases(String)
    case here(Bool)

    var discriminator: Discriminator {
        switch self {
        case .weGot: return .weGot
        case .someCases: return .someCases
        case .here: return .here
        }
    }

    enum Discriminator: String, CaseIterable {
        case weGot, someCases, here
    }

}

There are a wide range of use cases where this is needed (wiring up in-app settings preferences, log message shorthand, etc). This is boilerplate that, as far as my understanding goes, could be automatically synthesized by the compiler:

enum Foo: Discriminated {
    case weGot(Int)
    case someCases(String)
    case here(Bool)
}

Any frozen enum with one or more associated values could be marked Discriminated. If it is, the compiler would synthesize:

  • An enum Discriminator nested type within that enum
  • A var discriminator: Discriminator property on that enum

The Discriminator enum would have a raw value of String (raw values would be exactly match the case names) and would be CaseIterable.

The compiler would emit a build error on an enum marked Discriminated if any of the following are true:

  • The enum isn't frozen
  • The enum has no cases with associated values
12 Likes

I suggest reading this relevant thread from a few months back where this idea amongst others were discussed in depth.

tl;dr; introducing CasePaths (and PartialCasePaths by extension) is probably the most fitting solution to this issue.

8 Likes

This is something I’ve also wanted several times. However, AFAIK @frozen is only allowed when compiling in library evolution mode, so it doesn’t seem this would be very useful to most apps or packages. Why does it have to be limited to @frozen enums?

2 Likes

I also raised this here: [Idea] Enum IntCase, StringCase

This change would be enormously useful for me. I make heavy use of enums, and it's often useful to access a string/int representation of a given case (e.g. for custom enum Codable implementations)

In those instances do you need var discriminator: Discriminator (enum value) or just var string: String (the raw value like "weGot")? If it is the former, can you provide a mini sample code to show it?

The string itself is easy to get, smth like: "\(Foo.weGot(123))" to get "weGot(123)" and then remove the brackets and what's in them.

I think this is great. I don't see why you would need the enum to be @frozen though. Seems like you could have the Discriminator just be @frozen or not depending on if the enum is frozen or not. If it's not frozen, then the Discriminator isn't frozen and you would have to deal with that when using it.

2 Likes