[Idea] Enum IntCase, StringCase

I’m extensively using Enums (with associated values) as part of a Swift server backend, whereby multiple instances of the same application are talking to each other over the network.

Codable messages are encoded on one end, and decoded on the other. It’s useful for me to be able to retrieve the name or index of an enum case to simplify coding, and I find myself writing lots of boilerplate that could easily instead by synthesised by the compiler.

Here’s an example:

enum Event {
    case message(_ message: String)
    case ping
    case userConnected(_ user: User)
    
    // Could be auto-synthesised by compiler
    enum IntCase: Int, Codable {
        case message
        case ping
        case userConnected
    }

    // Could be auto-synthesised by compiler
    enum StringCase: String, Codable {
        case message
        case ping
        case userConnected
    }

    // Could be auto-synthesised by compiler
    var intCase: IntCase {
        switch self {
        case .message:       return .message
        case .ping:          return .ping
        case .userConnected: return .userConnected
        }
    }
    
    // Could be auto-synthesised by compiler
    var stringCase: StringCase {
        switch self {
        case .message:       return .message
        case .ping:          return .ping
        case .userConnected: return .userConnected
        }
    }
}

Perhaps this could be opt-in via protocol conformance.

Both now evaluate to true:

Event.message("hello").stringCase == "message"
Event.message("hello").intCase == 0

I can provide further examples of how this proves useful for custom coding of enums with associated values if there is interest...

What do you mean by “simplify coding”?

Once the Event enum has been decoded (in the Codable sense - from some serialised data), it is an enum and you can use the language’s built-in features (switch, if case, etc), instead of comparing integers and strings.

You can do something to the effect of this, below. It's a lot clearer to the developer what's going on rather than switching over integers.

public init(from decoder: Decoder) throws {
    var container = try decoder.unkeyedContainer()
    let type = try container.decode(IntCase.self)
    
    switch type {
    case .message:
        self = .message(try container.decode())
    case .ping:
        self = .ping
    case .userConnected:
        self = .userConnected(try container.decode())
}

public func encode(to encoder: Encoder) throws {
    var container = encoder.unkeyedContainer()
    try container.encode(intCase)
    
    switch self {
    case .message(let string):
        try container.encode(string)
    case .ping:
        break
    case .userConnected(let user):
        try container.encode(user)
    }
}

(Note this code doesn't conform exactly to out of the box Codable, as I'm using a few extensions to ease things, but you get the idea)

I see. Well, there have frequently been topics about extending Codable synthesis to include enums with associated values (I think this is the latest one). Perhaps that, or some variant of it, would suit your needs.

I'm not convinced there'll be an automatic Codable behaviour for enums (+associated values) that'll be customisable enough to accommodate all the ways people want to serialise their data. The linked pitch for example, assumes everyone wants a 'key' field in the generated output.

People are always going to want customisable Codable implementations, and something like this would allow people to do so in a clear and concise way for enums.

1 Like

Hello

I'd like to know how I can implement something like the enums from Swift into C# MyBPCreditcard

My use case: in the code you can load List<Something> from multiple different sources. From all sources, I receive the same list of Somethings

I can either retrieve it from API1, but I'd have to pass 1parameters to it. I can also load it from API2 but I'd have to pass 2 parameters to it. I can load it from my local database.

so essentially my function looks like

List<Something> LoadSomethings(Query query) {
    switch query {
        // implement cases
    }
     
     // do something with results afterwards
     return results
}

in Swift you can easily do

enum Query {
  case Api1(query1: Int)
  case Api2(query1: Int, query2: String)
  case Locally
}

What would be the equivalent solution in C# 9?

You’ll have to ask a C# community, I’m afraid. This community is only concerned with Swift.