<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">Although I appreciate the intent, I too find the proposed sugar far more noisy and harder to read than the more typical approach.</div><div class=""><br class=""></div><div class="">But:</div><div class=""><br class=""></div><div class=""><div class="">TLDR; Simplifying the accessing of enum associated values would be worthy of some syntactic sugar in my opinion.</div><div class=""><br class=""></div></div><div class="">One area of enums that I’d love to see some sugar wrapped around (and perhaps this has already been discussed previously?) is extracting associated values.</div><div class=""><br class=""></div><div class="">There are many times where, given an enum like:</div><div class=""><br class=""></div><div class=""><font face="Menlo" class="">enum Feedback {</font></div><div class=""><font face="Menlo" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>case ok</font></div><div class=""><font face="Menlo" class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>case info(String)</font></div><div class=""><font face="Menlo" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>case warning(String, Location)</font></div><div class=""><font face="Menlo" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>case error(String, Location)</font></div><div class=""><font face="Menlo" class="">}</font></div><div class=""><br class=""></div><div class="">I’d love it if we could tag the associated values with some semantic accessor, perhaps borrowed from tuples:</div><div class=""><br class=""></div><div class=""><div class=""><font face="Menlo" class="">enum Feedback {</font></div><div class=""><font face="Menlo" class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>case ok</font></div><div class=""><font face="Menlo" class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>case info(msg: String)</font></div><div class=""><font face="Menlo" class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>case warning(msg: String, loc: Location)</font></div><div class=""><font face="Menlo" class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>case error(msg: String, loc: Location)</font></div><div class=""><font face="Menlo" class="">}</font></div></div><div class=""><br class=""></div><div class="">then:</div><div class=""><br class=""></div><div class=""><font face="Menlo" class="">let foo = self.getSomeFeedback() // -> Feedback</font></div><div class=""><font face="Menlo" class="">if let msg = foo.msg { // since not all cases can hold a ‘msg’ .msg is an Optional</font></div><div class=""><font face="Menlo" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>print(foo)</font></div><div class=""><font face="Menlo" class="">}</font></div><div class=""><br class=""></div><div class="">I know this is a trivial example, since there are only 4 cases, but I have enums with many more cases where many of the cases share some common semantic themes, and producing large switch statements to exercise all of the possible patterns that might hold a given associated value can be verbose to the point of illegibility.</div><div class=""><br class=""></div><div class="">I know there is also the (IMHO terrible) "if let case” incantation, but I can never remember how it is spelled, and its even harder to read, IMHO.</div><div class=""><br class=""></div><div class="">—Karim</div><div class=""><br class=""></div><br class=""><blockquote type="cite" class="">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.<br class=""><br class="">A few conceptual questions:<br class=""><br class="">How does this interact with versioned cases? <br class="">What about enums that carry values?<br class=""><br class="">~Robert Widmann<br class=""><br class="">2017/01/06 23:59、Tim Shadel via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> のメッセージ:<br class=""><br class=""><blockquote type="cite" class="">Idea: Consolidate the Code for Each Case in an Enum<br class=""><br class=""># Motivation:<br class=""><br class="">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.<br class=""><br class=""># Background:<br class=""><br class="">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.<br class=""><br class=""># Proposed Solution:<br class=""><br class="">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.).<br class=""><br class="">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.<br class=""><br class="">```<br class="">protocol State {<br class=""> mutating func react(to event: Event)<br class="">}<br class=""><br class="">enum TokenState: State, CustomStringConvertible {<br class=""><br class=""> case expired(at: Date)<br class=""> case validated(token: String)<br class=""><br class=""> var description: String {<br class=""> switch self {<br class=""> case let .expired(at):<br class=""> return "Expired at \(at)"<br class=""> case let .validated(token):<br class=""> return "Token \(token) has been validated."<br class=""> }<br class=""> }<br class=""><br class=""> mutating func react(to event: Event) {<br class=""> switch self {<br class=""> case .expired:<br class=""> switch event {<br class=""> case _ as TokenRefreshed:<br class=""> self = .validated(token: event.token)<br class=""> default:<br class=""> break<br class=""> }<br class=""> case .validated:<br class=""> switch event {<br class=""> case _ as TokenRejected:<br class=""> self = .expired(at: Date())<br class=""> case _ as UserLoggedOut:<br class=""> self = .expired(at: Date())<br class=""> default:<br class=""> break<br class=""> }<br class=""> }<br class=""> }<br class=""><br class="">}<br class="">```<br class=""><br class="">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.<br class=""><br class="">```<br class="">enum TokenState: State, CustomStringConvertible {<br class=""> case expired(at: Date)<br class=""> case validated(token: String)<br class="">}<br class=""><br class="">extension TokenState.expired {<br class=""><br class=""> var description: String {<br class=""> return "Token expired at \(<a href="http://self.at/" class="">self.at</a>)"<br class=""> }<br class=""><br class=""> mutating func react(to event: Event) {<br class=""> switch event {<br class=""> case _ as TokenRefreshed:<br class=""> self = .untested(token: event.token)<br class=""> default:<br class=""> break<br class=""> }<br class=""> }<br class=""><br class="">}<br class=""><br class="">extension TokenState.validated {<br class=""><br class=""> var description: String {<br class=""> return "Token \(self.token) has been validated."<br class=""> }<br class=""><br class=""> mutating func react(to event: Event) {<br class=""> switch event {<br class=""> case _ as TokenRejected:<br class=""> self = .expired(at: Date())<br class=""> case _ as UserLoggedOut:<br class=""> self = .expired(at: Date())<br class=""> default:<br class=""> break<br class=""> }<br class=""> }<br class=""><br class="">}<br class="">```<br class=""><br class="">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.<br class=""><br class="">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.<br class=""><br class="">```<br class="">extension TokenState.expired {<br class=""><br class=""> var description: String {<br class=""> return "Token expired at \(<a href="http://self.at/" class="">self.at</a>)"<br class=""> }<br class=""><br class=""> <<< error: react(to:) must be exhaustively defined. Missing implementation for case .expired<br class="">}<br class="">```<br class=""><br class="">Can be mitigated with:<br class=""><br class="">```<br class="">enum TokenState: State, CustomStringConvertible {<br class=""> case expired(at: Date)<br class=""> case validated(token: String)<br class=""><br class=""> // This becomes the `default` branch in the generated `switch`<br class=""> mutating func react(to event: Event) {<br class=""> print("Ignoring \(event) in case \(self)")<br class=""> }<br class="">}<br class="">```<br class=""><br class="">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.<br class=""><br class="">Thoughts?<br class=""><br class="">--Tim<br class="">_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></blockquote></blockquote></div></div></div><br class=""></body></html>