[swift-evolution] Consolidate Code for Each Case in Enum

Jay Abbott jay at abbott.me.uk
Wed Jan 11 19:43:53 CST 2017


I like the idea behind this, but I think the proposed syntax abuses
extension, which applies to types not individual cases. Putting the code
outside the enum also seems wrong, and it’s difficult to see how the
compiler would handle it, in particular ensuring exhaustiveness. So I have
come up with an alternate syntax using the example from the proposal that I
think works a bit better (or at least might inspire someone else to improve
it further):

enum TokenState {
    case expired(at: Date)
    case validated(token: String)

    caseprotocol { // (1)
        mutating func react(to event: Event)
        var description: String
    }
    caseimpl<.expired(let at)> { // (2)
        var description: String {
            return "Expired at \(at)"
        }
        mutating func react(to event: Event) {
            switch event {
            case _ as TokenRefreshed:
                self = .validated(token: event.token)
            default: break
            }
        }
    }
    caseimpl<.validated(let token)> { // (3)
        var description: String {
            return "Token \(token) has been validated."
        }
        mutating func react(to event: Event) {
            switch event {
            case _ as TokenRejected:
                self = .expired(at: Date())
            case _ as UserLoggedOut:
                self = .expired(at: Date())
            default: break
            }
        }
    }
    // (4)
}

I find this easier to parse manually, and I think the compiler would too…

   - At (1) it is equivalent to defining a normal protocol outside the
   enum. The enum itself would implicitly conform to this protocol. Calculated
   properties would be implicitly get-only in the protocol.
   - At (2) and (3) this would be equivalent to defining a static object
   that conforms to a compiler-modified version of the protocol, with static
   implementations of the getters/functions. Mutating functions would have an
   inout ref to self and they would all have any associated values sent in
   as per the let in the caseimpl declaration. The body would come directly
   from the programmer code.
   - At (4) the compiler would generate the enum’s implementation to
   conform to the protocol, this would switch on self and call the
   appropriate static functions. As per the original proposal.

It might be good if you don’t have to repeat all the func signatures in
each caseimpl - I considered a different syntax where you defined a casefunc
(similar to a typealias) like casefunc ReactTo = mutating func react(to
event: Event) then in the caseimpl you could just do ReactTo = { func body
here } but it didn’t seem to fit. Hopefully someone else will have some
ideas to reduce the repetition.
​
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170112/bb372b8c/attachment.html>


More information about the swift-evolution mailing list