[swift-evolution] Consolidate Code for Each Case in Enum
Derrick Ho
wh1pch81n at gmail.com
Sun Jan 8 01:50:58 CST 2017
Correct me if I am wrong but currently there are only two ways to extract
the value of an associated type.
// 1
switch n {
case foo(let value):
print(value)
}
// 2
if case foo(let value) = n {
print(value)
}
I think it would be nice to have another way. Maybe a tuple-like pattern.
let value = n.foo.0 // returns value as an optional.
If this can already be done, ignore me.
On Sun, Jan 8, 2017 at 2:20 AM Robert Widmann via swift-evolution <
swift-evolution at swift.org> wrote:
> I don't think I've ever wanted to distribute the patterns of a switch
> statement across multiple files. It seems like you want an enum of enums
> if the code you're writing needs this kind of chunking. Distributing cases
> is also far more brittle than the existing local switch; failing to include
> a file in the build that covers necessary cases now becomes a module-level
> error rather than a statement-local one. Finally, the proposal seems to do
> the opposite of consolidate and simplify code by introducing quite a lot of
> syntax around what it aims to do, and by muddying the meaning of a keyword
> that was previously only meant for types.
>
> A few conceptual questions:
>
> How does this interact with versioned cases?
> What about enums that carry values?
>
> ~Robert Widmann
>
> 2017/01/06 23:59、Tim Shadel via swift-evolution <swift-evolution at swift.org>
> のメッセージ:
>
> Idea: Consolidate the Code for Each Case in an Enum
>
>
>
> # Motivation:
>
>
>
> Consolidate all code related to a single enum case in one spot. This makes
> it easier to ensure that all the pieces mesh coherently across that one
> case.
>
>
>
> # Background:
>
>
>
> Enum cases _feel_ like separately defined, but tightly related structs
> because each case can have distinct associated values. They have special
> privileges that a family of structs doesn't have, like `self = .otherCase`.
> Enums are really awesome.
>
>
>
> # Proposed Solution:
>
>
>
> Any `func` or dynamic `var` that provides a unique response per `case`
> uses a `switch` to do so. I propose to hide that standard `switch` behind
> some syntactic sugar. Possibly `extension MyEnum.myCase`, assuming that
> nothing extra is allowed there (protocol conformance, generic constraints,
> etc.).
>
>
>
> Here's a typical example of a (simplified) enum that represents 2 states,
> and conforms to 2 protocols, each requiring different dynamic values based
> on the case of the enum. In both places, an outer `switch` is used to
> select the current enum case, and the logic within each branch further
> determines the value returned.
>
>
>
> ```
>
> protocol State {
>
> mutating func react(to event: Event)
>
> }
>
>
>
> enum TokenState: State, CustomStringConvertible {
>
>
>
> case expired(at: Date)
>
> case validated(token: String)
>
>
>
> var description: String {
>
> switch self {
>
> case let .expired(at):
>
> return "Expired at \(at)"
>
> case let .validated(token):
>
> return "Token \(token) has been validated."
>
> }
>
> }
>
>
>
> mutating func react(to event: Event) {
>
> switch self {
>
> case .expired:
>
> switch event {
>
> case _ as TokenRefreshed:
>
> self = .validated(token: event.token)
>
> default:
>
> break
>
> }
>
> case .validated:
>
> switch event {
>
> case _ as TokenRejected:
>
> self = .expired(at: Date())
>
> case _ as UserLoggedOut:
>
> self = .expired(at: Date())
>
> default:
>
> break
>
> }
>
> }
>
> }
>
>
>
> }
>
> ```
>
>
>
> If we instead allow all the code for each enum case to be consolidated,
> this new code looks much more like the rest of the code we write in Swift.
> Real world enums frequently have many more cases, and as the number of enum
> cases grows consolidating all their logic is increasingly helpful. The
> following proposal is identical to the code above, it simply "hides" the
> outer switch statement of each value.
>
>
>
> ```
>
> enum TokenState: State, CustomStringConvertible {
>
> case expired(at: Date)
>
> case validated(token: String)
>
> }
>
>
>
> extension TokenState.expired {
>
>
>
> var description: String {
>
> return "Token expired at \(self.at)"
>
> }
>
>
>
> mutating func react(to event: Event) {
>
> switch event {
>
> case _ as TokenRefreshed:
>
> self = .untested(token: event.token)
>
> default:
>
> break
>
> }
>
> }
>
>
>
> }
>
>
>
> extension TokenState.validated {
>
>
>
> var description: String {
>
> return "Token \(self.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
>
> }
>
> }
>
>
>
> }
>
> ```
>
>
>
> I've also shown automatic binding of each case's associated values to
> properties available on `self` ... but maybe it's better if they're bound
> to variable references captured the way a closure does. I'm not an expert
> in this part.
>
>
>
> Back to the meat of the idea, what happens when a case isn't extended, or
> only partially extended? Because it's simply a fancy `switch`, it still
> must be exhaustive or provide a `default` branch.
>
>
>
> ```
>
> extension TokenState.expired {
>
>
>
> var description: String {
>
> return "Token expired at \(self.at)"
>
> }
>
>
>
> <<< error: react(to:) must be exhaustively defined. Missing
> implementation for case .expired
>
> }
>
> ```
>
>
>
> Can be mitigated with:
>
>
>
> ```
>
> enum TokenState: State, CustomStringConvertible {
>
> case expired(at: Date)
>
> case validated(token: String)
>
>
>
> // This becomes the `default` branch in the generated `switch`
>
> mutating func react(to event: Event) {
>
> print("Ignoring \(event) in case \(self)")
>
> }
>
> }
>
> ```
>
>
>
> Note that this implementation for the `default` branch is just that. This
> is not creating a superclass/subclass relationship between the `enum` and
> the `case`, it's merely a convenient way to construct a `switch` statement.
> I'm not proposing to deprecate any existing source, merely introduce a more
> convenient form of a very typical pattern, so I hope it is
> source-compatible by the definition you guys are using.
>
> Thoughts?
>
> --Tim
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170108/e3a6f423/attachment.html>
More information about the swift-evolution
mailing list