Interesting proposal Tim. So instead of repeating the enum cases multiple times we repeat the functions multiple times?
I feel like this merely flipping the complexity but not really getting rid of it. On Tue, Jan 10, 2017 at 8:08 PM Tim Shadel via swift-evolution < [email protected]> wrote: > OK. I've taken the most recent changes from this thread and put together a > draft for a proposal. > > https://gist.github.com/timshadel/5a5a8e085a6fd591483a933e603c2562 > > I'd appreciate your review, especially to ensure I've covered all the > important scenarios. I've taken the 3 associated value scenarios (none, > unlabeled, labeled) and shown them in each example (calculated value, func, > default, error). I've included the raw text below, without any syntax > highlighting. > > My big question is: does the error case in the last example affect ABI > requirements, in order to display the error at the correct case line? I > assume it doesn't, but that's an area I don't know well. > > Thanks! > > Tim > > =============== > > # Enum Case Blocks > > * Proposal: SE-XXXX > * Authors: [Tim Shadel](https://github.com/timshadel) > * Review Manager: TBD > * Status: **TBD** > > ## Motivation > > Add an optional syntax to declare all code related to a single `case` in > one spot. For complex `enum`s, this makes it easier to ensure that all the > pieces mesh coherently across that one case, and to review all logic > associated with a single `case`. This syntax is frequently more verbose in > order to achieve a more coherent code structure, so its use will be most > valuable in complex enums. > > Swift-evolution thread: [Consolidate Code for Each Case in Enum]( > https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170102/029966.html > ) > > ## Proposed solution > > Allow an optional block directly after the `case` declaration on an > `enum`. Construct a hidden `switch self` statement for each calculated > value or `func` defined in any case block. Use the body of each such > calculated value in the hidden `switch self` under the appropriate case. > Because switch statements must be exhaustive, the calculated value or > `func` must be defined in each case block or have a `default` value to > avoid an error. Defining the `func` or calculated value outside a case > block defines the default case for the `switch self`. To reference an > associated value within any of the items in a case block requires the value > be labeled, or use a new syntax `case(_ label: Type)` to provide a > local-only name for the associated value. > > ## Examples > > All examples below are evolutions of this simple enum. > > ```swift > enum AuthenticationState { > case invalid > case expired(Date) > case validated(token: String) > } > ``` > > ### Basic example > > First, let's add `CustomStringConvertible` conformance to our enum. > > ```swift > enum AuthenticationState: CustomStringConvertible { > > case invalid { > var description: String { return "Authentication invalid." } > } > > case expired(_ expiration: Date) { > var description: String { return "Authentication expired at > \(expiration)." } > } > > case validated(token: String) { > var description: String { return "The authentication token is > \(token)." } > } > > } > ``` > > This is identical to the following snippet of Swift 3 code: > > ```swift > enum AuthenticationState: CustomStringConvertible { > > case invalid > case expired(Date) > case validated(token: String) > > var description: String { > switch self { > case invalid: > return "Authentication invalid." > case let expired(expiration): > return "Authentication expired at \(expiration)." > case let validated(token): > return "The authentication token is \(token)." > } > } > > } > ``` > > ### Extended example > > Now let's have our enum conform to this simple `State` protocol, which > expects each state to be able to update itself in reaction to an `Event`. > This example begins to show how this optional syntax give better coherence > to the enum code by placing code related to a single case in a single > enclosure. > > ```swift > 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 > } > } > } > > } > ``` > > This becomes identical to the following Swift 3 code: > > ```swift > enum AuthenticationState: State, CustomStringConvertible { > > case invalid > case expired(Date) > case validated(token: String) > > var description: String { > switch self { > case invalid: > return "Authentication invalid." > case let expired(expiration): > return "Authentication expired at \(expiration)." > case let validated(token): > return "The authentication token is \(token)." > } > } > > mutating func react(to event: Event) { > switch self { > case invalid: { > switch event { > case let login as UserLoggedIn: > self = .validated(token: login.token) > default: > break > } > } > case let expired(expiration) { > switch event { > case let refreshed as TokenRefreshed: > self = .validated(token: refreshed.token) > default: > break > } > } > case let validated(token) { > 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 > } > } > } > > } > ``` > > ### Default case example > > Let's go back to the simple example to demonstrate declaring a default > case. > > ```swift > enum AuthenticationState: CustomStringConvertible { > > var description: String { return "" } > > case invalid > case expired(Date) > case validated(token: String) { > var description: String { return "The authentication token is > \(token)." } > } > > } > ``` > > Is identical to this Swift 3 code: > > ```swift > enum AuthenticationState: CustomStringConvertible { > > case invalid > case expired(Date) > case validated(token: String) > > var description: String { > switch self { > case let validated(token): > return "The authentication token is \(token)." > default: > return "" > } > } > > } > ``` > > ### Error example > > Finally, here's what happens when a case fails to add a block when no > default is defined. > > ```swift > enum AuthenticationState: CustomStringConvertible { > > case invalid <<< error: description must be exhaustively defined. > Missing block for case .invalid. > > case expired(Date) <<< error: description must be exhaustively > defined. Missing block for case .expired. > > case validated(token: String) { > var description: String { return "The authentication token is > \(token)." } > } > > } > ``` > > ## Source compatibility > > No source is deprecated in this proposal, so source compatibility should > be preserved. > > ## Effect on ABI stability > > Because the generated switch statement should be identical to one that can > be generated with Swift 3, I don't foresee effect on ABI stability. > > Question: does the error case above affect ABI requirements, in order to > display the error at the correct case line? > > ## Alternatives considered > > Use of the `extension` keyword was discussed and quickly rejected for > numerous reasons. > > > On Jan 9, 2017, at 2:22 PM, Tony Allevato <[email protected]> wrote: > > I like that approach a lot (and it would be nice to use separate labels > vs. argument names in the case where they do have labels, too). > > Enum cases with associated values are really just sugar for static methods > on the enum type *anyway* with the added pattern matching abilities, so > unifying the syntax seems like a positive direction to go in. > > > On Mon, Jan 9, 2017 at 1:20 PM Tim Shadel <[email protected]> wrote: > > Yeah, that's much nicer than what I just sent! :-D > > > On Jan 9, 2017, at 2:16 PM, Sean Heber <[email protected]> wrote: > > > > I can’t speak for Tim, but I’d suggest just unifying the case syntax > with functions so they become: > > > > case foo(_ thing: Int) > > > > And if you don’t actually need to ever *use* it by name in your enum > properties/functions (if you even have any), then you could leave it out > and write it like it is now, but that’d become “sugar”: > > > > case foo(Int) > > > > l8r > > Sean > > > > > >> On Jan 9, 2017, at 3:11 PM, Tony Allevato <[email protected]> > wrote: > >> > >> Ah, my apologies—the syntax highlighting in the thread was throwing off > my e-mail client and I was having trouble reading it. > >> > >> Associated values don't necessarily have to have names: I can write > "case .foo(Int)". Since your examples use the associated value label as the > name of the value inside the body, how would you handle those label-less > values? > >> > >> > >> On Mon, Jan 9, 2017 at 1:06 PM Tim Shadel <[email protected]> wrote: > >> There are examples of associated values in the proposed syntax. Which > parts should I provide more detail on? > >> > >>> On Jan 9, 2017, at 1:43 PM, Tony Allevato via swift-evolution < > [email protected]> wrote: > >>> > >>> While I do like the consolidated syntax more than most of the > alternatives I've seen to address this problem, any proposed solution also > needs to address how it would work with cases that have associated values. > That complicates the syntax somewhat. > >>> > >>> > >>> On Mon, Jan 9, 2017 at 12:37 PM Sean Heber via swift-evolution < > [email protected]> wrote: > >>> > >>>> On Jan 9, 2017, at 2:28 PM, Guillaume Lessard via swift-evolution < > [email protected]> wrote: > >>>> > >>>> > >>>>> On 9 janv. 2017, at 10:54, Tim Shadel via swift-evolution < > [email protected]> wrote: > >>>>> > >>>>> Enums get large, and they get complicated because the code for each > case gets sliced up and scattered across many functions. It becomes a "one > of these things is not like the other" situation because writing functions > inside enums is unlike writing functions in any other part of Swift code. > >>>> > >>>> The problem I see with this is that enums and their functions > inherently multiply each other. If I have 3 cases and 3 functions or > properties, there are 9 implementation details, no matter how they're > organized. There can be 3 functions/properties, each with a 3-case switch, > or there can be 3 enum cases each with 3 strange, partial > functions/properties. > >>>> > >>>> I can see why someone might prefer one over the other, but is either > way truly better? The current way this works at least has the merit of not > requiring a special dialect for enums. > >>> > >>> I’m not sure how to argue this, but I feel pretty strongly that > something more like this proposed organization *is* actually better. That > said, I do not think this conflicts with the current design of enums, > however, so this is likely purely additive. The current design makes some > situations almost comically verbose and disorganized, IMO, but it *is* > right for other situations. We may want to have both. > >>> > >>> l8r > >>> Sean > >>> _______________________________________________ > >>> swift-evolution mailing list > >>> [email protected] > >>> https://lists.swift.org/mailman/listinfo/swift-evolution > >>> _______________________________________________ > >>> swift-evolution mailing list > >>> [email protected] > >>> https://lists.swift.org/mailman/listinfo/swift-evolution > >> > > > > > _______________________________________________ > swift-evolution mailing list > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
