I have mixed feelings about this. I would like to see a solution to the 
exploding switch statements in an enum, and we have talked about that before on 
this list. However the solution as suggested seems deficient to me.

First, A developer would have to look at an enum “extension” in order to be 
able to know what to do with the enum. And those extensions can be in different 
files? So at the very least the enum would need to carry the full spec of what 
it can do.

I also dislike the use of the keyword “extension” here. It does not extend 
anything imo.

And thirdly, I dislike having to repeat the function definitions for every enum 
case, that is even more verbose than “switch case”.

Other than that, I would support the simplification of enums as such :-)

Regards,
Rien

Site: http://balancingrock.nl
Blog: http://swiftrien.blogspot.com
Github: http://github.com/Swiftrien
Project: http://swiftfire.nl




> On 07 Jan 2017, at 07:59, Tim Shadel via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
> 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@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to