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

Anton Zhilin antonyzhilin at gmail.com
Wed Jan 11 14:57:16 CST 2017


Wouldn’t protocols be a better solution in this case? If little to no logic
can be shared between enum cases, why have the enum in the first place?

Your variant:

protocol State {

    mutating func react(to event: Event)
}
enum AuthenticationState: State, CustomStringConvertible {

    case invalid {
        var description: String { return "Authentication invalid." }

        mutating func react(to event: Event) {
            switch event {

            case let login as UserLoggedIn:
                self = .validated(token: login.token)
            default:
                break
            }
        }
    }

    case expired(_ expiration: Date) {
        var description: String { return "Authentication expired at
\(expiration)." }

        mutating func react(to event: Event) {
            switch event {
            case let refreshed as TokenRefreshed:

                self = .validated(token: refreshed.token)

            default:
                break
            }
        }
    }

    case validated(token: String) {

        var description: String { return "The authentication token is
\(token)." }

        mutating func react(to event: Event) {
            switch event {

            case let expiration as TokenExpired:
                print("Expiring token: \(token)")
                self = .expired(expiration.date)
            case _ as TokenRejected:
                self = .invalid
            case _ as UserLoggedOut:
                self = .invalid
            default:
                break
            }
        }
    }

}

My suggestion:

public protocol State {

    mutating func react(to event: Event)
}

@closed protocol AuthenticationState : State, CustomStringConvertible { }
struct InvalidAuthenticationState : AuthenticationState {
    var description: String { return "Authentication invalid." }

    mutating func react(to event: Event) {
        switch event {

        case let login as UserLoggedIn:
            self = .validated(token: login.token)
        default:
            break
        }
    }
}
struct ExpiredAuthenticationState : AuthenticationState {
    var expiration: Date

    var description: String { return "Authentication expired at
\(expiration)." }

    mutating func react(to event: Event) {
        switch event {
        case let refreshed as TokenRefreshed:

            self = .validated(token: refreshed.token)

        default:
            break
        }
    }
}
struct ValidatedAuthenticationState : AuthenticationState {
    var token: String

    var description: String { return "The authentication token is \(token)." }

    mutating func react(to event: Event) {
        switch event {

        case let expiration as TokenExpired:
            print("Expiring token: \(token)")
            self = .expired(expiration.date)
        case _ as TokenRejected:
            self = .invalid
        case _ as UserLoggedOut:
            self = .invalid
        default:
            break
        }
    }
}

If AuthenticationState is not public, then compiler can make an
optimization and turn existentials and indirect calls into an enum,
essentially.
We can even split public protocols into open and public, as we did with
classes, to allow for expressing this intent more explicitly.

But pattern matching on structs is impossible—we can change that with a
separate proposal. For example, we can allow destructuring
structs/enums/classes by any combination of their properties:

struct S {
    var foo: Int
    var bar: Double
    var buz: String { return "42" }
}
let s = S(foo: 42, bar: 42.0)
let S(foo: x, buz: z) = s

​
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170111/84966020/attachment.html>


More information about the swift-evolution mailing list