I would like something along these lines. I would suggest going farther and do 
something like this if possible to avoid repeating the type information all 
over the place:

enum OneOnOneField: Int {
        let title: String
        let placeholder: String
        let image: UIImage

        case agenda {
                title: NSLocalizedString("Agenda", comment: "One on one field 
header")
                placeholder: NSLocalizedString("Add an agenda", comment: "One 
on one field placeholder”)
                image: #imageLiteral(resourceName: "Agenda-Small”)
        }

        // etc
}

l8r
Sean



> On Jan 9, 2017, at 11:54 AM, Tim Shadel via swift-evolution 
> <[email protected]> wrote:
> 
> It seems like my original (simplified) examples didn't clearly highlight what 
> the problem I'm focused on solving.
> 
> 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.
> 
> Also, to be clear, my goal is _not_ code brevity. It is coherence, the 
> property where related code is located together. Some increase in code 
> verbosity is acceptable to make code more coherent, since that leads to 
> long-term maintainability.
> 
> I've pulled out a few of the larger enums I've seen in code to try to 
> illustrate this. Along the way, I've made a few alterations based on the 
> comments I've seen come through. (Rien & Robert: I've pushed the definitions 
> inside the declaration, to ensure they don't end up in other files since that 
> was never my intention; Rien & Daniel: I've altered the syntax to open a 
> brace right after the case declaration making everything outside it the 
> default, and I like that better).
> 
> Here's an enum used to consolidate the descriptions of UI elements for a 
> screen, allowing the datasource to alter their order, presentation, and 
> visibility while keeping the set of possible fields clean and finite. These 
> enum values are used much like singletons.
> 
> enum OneOnOneField: Int {
> 
>     
> case agenda
>     case summary
>     case date
>     case notes
> 
>     struct Info {
> 
>         var title
> : String
> 
>         var placeholder
> : String
> 
>         var image
> :
>  UIImage
>     
> }
> 
> 
>     var info
> : Info {
> 
>         
> switch self {
> 
>         
> case .agenda:
> 
>             
> return Info(
> 
>                 title
> : NSLocalizedString("Agenda", comment: "One on one field header"),
> 
>                 placeholder
> : NSLocalizedString("Add an agenda", comment: "One on one field placeholder"),
> 
>                 image
> : #imageLiteral(resourceName: "Agenda-Small"))
> 
>         
> case .summary:
> 
>             
> return Info(
> 
>                 title
> : NSLocalizedString("Summary", comment: "One on one field header"),
> 
>                 placeholder
> : NSLocalizedString("Add a summary", comment: "One on one field placeholder"),
> 
>                 image
> : #imageLiteral(resourceName: "Summary-Small"))
> 
>         
> case .date:
> 
>             
> return Info(title: "", placeholder: "", image: UIImage())
> 
>         
> case .notes:
> 
>             
> return Info(title: NSLocalizedString("Personal Notes", comment: "Title for 
> personal notes screen"), placeholder: "", image: UIImage())
> 
>         
> }
> 
>     
> }
> }
> Consolidating them could instead look something like this:
> 
> enum OneOnOneField: Int {
> 
> 
>     var title
> : String { return "" }
> 
>     var placeholder
> : String { return "" }
> 
>     var image
> : UIImage { return UIImage() }
> 
> 
>     
> case agenda {
>         var title: String { return NSLocalizedString("Agenda", comment: "One 
> on one field header") }
> 
>         var placeholder
> : String { return NSLocalizedString("Add an agenda", comment: "One on one 
> field placeholder") }
> 
>         var image
> : UIImage { return #imageLiteral(resourceName: "Agenda-Small") }
> 
>     
> }
> 
> 
>     
> case summary {
>         var title: String { return NSLocalizedString("Summary", comment: "One 
> on one field header") }
> 
>         var placeholder
> : String { return NSLocalizedString("Add a summary", comment: "One on one 
> field placeholder") }
> 
>         var image
> : UIImage { return #imageLiteral(resourceName: "Summary-Small") }
> 
>     
> }
> 
> 
>     
> case date
> 
>     case notes {
>         var title: String { return NSLocalizedString("Personal Notes", 
> comment: "Title for personal notes screen") }
> 
>     
> }
> 
> 
> 
> }
> Here's an enum that implements the basics of a state machine for OAuth 2 
> token use, refreshing, and login. Some of its cases have associated values 
> and some don't.
> 
> enum TokenState: State {
> 
> 
>     
> case loading
>     case none
>     case expired(Date)
>     case untested(token: String)
>     case validated(token: String)
> 
>     var description: String {
> 
>         
> switch self {
> 
>         
> case .loading:
> 
>             
> return "Loading token from disk"
> 
>         
> case .none:
> 
>             
> return "No token found"
> 
>         
> case let .expired(at):
> 
>             
> return "Expired at \(at)"
> 
>         
> case let .untested(token):
> 
>             
> return "Received token \(token), but it hasn't been tested."
> 
>         
> case let .validated(token):
> 
>             
> return "Token \(token) has been validated."
> 
>         
> }
> 
>     
> }
> 
> 
>     mutating func react
> (to event: Event) {
> 
>         
> switch self {
> 
>         
> case .loading:
> 
>             
> switch event {
> 
>             
> case _ as TokenNotFound:
> 
>                 self 
> = .
> none
>             
> case let expired as TokenExpired:
> 
>                 self 
> = .expired(expired.at)
> 
>             
> case let loaded as TokenLoaded:
> 
>                 self 
> = .untested(token: loaded.token)
>             default:
> 
>                 
> break
> 
>             
> }
> 
>         
> case .none:
> 
>             
> switch event {
> 
>             
> case let loggedIn as UserLoggedIn:
> 
>                 self 
> = .untested(token: loggedIn.token)
>             default:
> 
>                 
> break
> 
>             
> }
> 
>         
> case .expired:
> 
>             
> switch event {
> 
>             
> case let refreshed as TokenRefreshed:
> 
>                 self 
> = .untested(token: refreshed.token)
> 
>             
> case _ as TokenRefreshErrored:
> 
>                 self 
> = .
> none
> 
>             default:
> 
>                 
> break
> 
>             
> }
> 
>         
> case let .untested(token):
> 
>             
> switch event {
> 
>             
> case _ as UserLoaded:
> 
>                 self 
> = .validated(token: token)
> 
>             
> case _ as TokenRejected:
> 
>                 self 
> = .expired(at: Date())
>             default:
> 
>                 
> break
> 
>             
> }
> 
>         
> case .validated:
> 
>             
> switch event {
> 
>             
> case _ as TokenRejected:
> 
>                 self 
> = .expired(Date())
> 
>             
> case _ as UserLoggedOut:
> 
>                 self 
> = .
> none
> 
>             default:
> 
>                 
> break
> 
>             
> }
> 
>         
> }
> 
>     
> }
> 
> 
>     
> static var initialState: TokenState {
> 
>         
> return .
> loading
>     
> }
> 
> 
> 
> }
> After consolidation, this becomes:
> 
> enum TokenState: State {
> 
> 
>     
> static var initialState: TokenState {
> 
>         
> return .
> loading
>     
> }
> 
> 
>     
> case loading {
>         var description: String {
> 
>             
> return "Loading token from disk"
> 
>         
> }
> 
> 
>         mutating func react
> (to event: Event) {
> 
>             
> switch event {
> 
>             
> case _ as TokenNotFound:
> 
>                 self 
> = .
> none
>             
> case let expired as TokenExpired:
> 
>                 self 
> = .expired(at: expired.at)
> 
>             
> case let loaded as TokenLoaded:
> 
>                 self 
> = .untested(token: loaded.token)
>             default:
> 
>                 
> break
> 
>             
> }
> 
>         
> }
> 
>     
> }
> 
> 
>     
> case none {
>         var description: String {
> 
>             
> return "No token found"
> 
>         
> }
> 
> 
>         mutating func react
> (to event: Event) {
> 
>             
> switch event {
> 
>             
> case let loggedIn as UserLoggedIn:
> 
>                 self 
> = .untested(token: loggedIn.token)
>             default:
> 
>                 
> break
> 
>             
> }
> 
>         
> }
> 
>     
> }
> 
> 
>     
> case expired(at: Date) {
>         var description: String {
> 
>             
> return "Expired at \(at)"
> 
>         
> }
> 
> 
>         mutating func react
> (to event: Event) {
> 
>             
> switch event {
> 
>             
> case let refreshed as TokenRefreshed:
> 
>                 self 
> = .untested(token: refreshed.token)
> 
>             
> case _ as TokenRefreshErrored:
> 
>                 self 
> = .
> none
> 
>             default:
> 
>                 
> break
> 
>             
> }
> 
>         
> }
> 
>     
> }
> 
> 
>     
> case untested(token: String) {
>         var description: String {
> 
>             
> return "Received token \(token), but it hasn't been tested."
> 
>         
> }
> 
> 
>         mutating func react
> (to event: Event) {
> 
>             
> switch event {
> 
>             
> case _ as UserLoaded:
> 
>                 self 
> = .validated(token: token)
> 
>             
> case _ as TokenRejected:
> 
>                 self 
> = .expired(at: Date())
>             default:
> 
>                 
> break
> 
>             
> }
> 
>         
> }
> 
>     
> }
> 
> 
>     
> case validated(token: String) {
>         var description: String {
> 
>             
> return "Token \(token) has been validated."
> 
>         
> }
> 
> 
>         mutating func react
> (to event: Event) {
> 
>             
> switch event {
> 
>             
> case _ as TokenRejected:
> 
>                 self 
> = .expired(at: Date())
> 
>             
> case _ as UserLoggedOut:
> 
>                 self 
> = .
> none
> 
>             default:
> 
>                 
> break
> 
>             
> }
> 
>         
> }
> 
>     
> }
> 
> 
> 
> }
> 
> 
> 
>> On Jan 8, 2017, at 12:22 PM, Derrick Ho via swift-evolution 
>> <[email protected]> wrote:
>> 
>> Currently we can write a helper method to aid in getting the values inside 
>> the enum associated value.  Below is a fully working implementation:
>> 
>> ```
>> enum Package {
>>      case box(String, Int)
>>      case circular(String)
>>      
>>      var associated: Associated {
>>              return Associated(package: self)
>>      }
>>      
>>      struct Associated {
>>              let box: (String, Int)?
>>              let circular: (String)?
>>              init(package: Package) {
>>                      switch package {
>>                      case .box(let b):
>>                              box = b
>>                              circular = nil
>>                      case .circular(let b):
>>                              box = nil
>>                              circular = b
>>                      }
>>              }
>>      }
>> }
>> 
>> let b = Package.box("square", 5)
>> b.associated.box?.0 // Optional("square")
>> b.associated.box?.1 // Optional(5)
>> b.associated.circular // nil
>> 
>> let c = Package.circular("round")
>> c.associated.box?.0 // nil
>> c.associated.box?.1 // nil
>> c.associated.circular // Optional("round")
>> ```
>> 
>> I had to wedge in a special type called "Associated" and had to write some 
>> boiler-plate code to get this effect.  It is quite predictable and can 
>> probably be done under the hood.  I would of course prefer syntactic sugar 
>> to simplify it and turn
>> ```
>> b.associated.box?.0
>> ```
>> into 
>> ```
>> b.box?.0
>> ```
>> 
>> On Sun, Jan 8, 2017 at 1:05 PM David Sweeris via swift-evolution 
>> <[email protected]> wrote:
>> 
>> On Jan 8, 2017, at 06:53, Karim Nassar via swift-evolution 
>> <[email protected]> wrote:
>> 
>>> 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.
>>> 
>>> There are many times where, given an enum like:
>>> 
>>> enum Feedback {
>>>     case ok
>>>     case info(String)
>>>     case warning(String, Location)
>>>     case error(String, Location)
>>> }
>>> 
>>> I’d love it if we could tag the associated values with some semantic 
>>> accessor, perhaps borrowed from tuples:
>>> 
>>> enum Feedback {
>>>     case ok
>>>     case info(msg: String)
>>>     case warning(msg: String, loc: Location)
>>>     case error(msg: String, loc: Location)
>>> }
>>> 
>>> then:
>>> 
>>> let foo = self.getSomeFeedback() // -> Feedback
>>> if let msg = foo.msg { // since not all cases can hold a ‘msg’ .msg is an 
>>> Optional
>>>     print(foo)
>>> }
>> 
>> Can't remember if it's come up before, but +1. I can't count how many times 
>> I've written something like:
>> enum Foo : CustomStringConvertible {
>>     case c1(T1)
>>     case c2(T2)
>>     ...
>>     case cN(TN)
>> 
>>     var description: String {
>>         switch self {
>>             case .c1(let val): return "\(val)"
>>             case .c2(let val): return "\(val)"
>>             ...
>>             case .cN(let val): return "\(val)"
>>         }
>>     }
>> }
>> 
>> Being able to simplify that to:
>> var description: String {
>>     let nilDesc = "some appropriate description"
>>     return "\(self.0 ?? nilDesc)"
>> }
>> 
>> Would be great.
>> 
>> - Dave Sweeris 
>> _______________________________________________
>> 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

Reply via email to