Possible to pass an enum 'type'?

I have some code now that essentially has three for loops that I'd like to shrink. I tried to write a small function to do it, but stuck on how to pass an enum value that normally takes an associated value as just a 'type', so I can associate the value in the routine.


I fully realize that I can probably create some other ErrorType subclass, or perhaps use a enum that has a tuple associated with it - I'm sure there are a vast number of ways to solve my problem (and I'll probably just use one shortly).


However, curiousity prompts me to post this, to see if there is in fact some way to modify my function parameter to fullfill the intention:


private enum RecommendationErrors: ErrorType {
  case StringError(String)
  case VarsError(String)
  case ImageError(String)
}

func parseRecommendations(item: [String: AnyObject]) throws -> [String: String] {
  var dict = [String: String]()
  var stringItems: [String]
  func process(d: [String: AnyObject], err: RecommendationErrors) {
     for s in stringItems {
        if let val = d[s] as? String {
           dict[s] = val
        } else {
           throw err(s) <<<--- compilee error
        }
     }
  }
  ...
Answered by tompelaia2 in 37446022

How about the following code? You can refer to the associated type enum via a closure. For example, you can pass: RecommendationErrors.StringError


private enum RecommendationErrors: ErrorType {
  case StringError(String)
  case VarsError(String)
  case ImageError(String)
}
func parseRecommendations(item: [String: AnyObject]) throws -> [String: String] {
  var dict = [String: String]()
  var stringItems: [String]
  func process(d: [String: AnyObject], err: (String)->RecommendationErrors) throws {
       for s in stringItems {
            if let val = d[s] as? String {
            dict[s] = val
            } else {
                 throw err(s)
            }
        }
  }
...
Accepted Answer

How about the following code? You can refer to the associated type enum via a closure. For example, you can pass: RecommendationErrors.StringError


private enum RecommendationErrors: ErrorType {
  case StringError(String)
  case VarsError(String)
  case ImageError(String)
}
func parseRecommendations(item: [String: AnyObject]) throws -> [String: String] {
  var dict = [String: String]()
  var stringItems: [String]
  func process(d: [String: AnyObject], err: (String)->RecommendationErrors) throws {
       for s in stringItems {
            if let val = d[s] as? String {
            dict[s] = val
            } else {
                 throw err(s)
            }
        }
  }
...

Brilliant!


Anyone else reading this, here is how to call process:


  try process(item, err: { (s: String)->RecommendationErrors in return RecommendationErrors.StringError(s) } )


EDIT: As tompelaia suggests, you can shorten this to:


try process(item, err: { RecommendationErrors.StringError($0) } )

Actually you can pass it simply as:


try process(item, err: RecommendationErrors.StringError)

HAH! I figured that out myself! I just came back to update my answer....but you beat me to it!


EDIT: I needed to wrap the closure in '{' and '}' - I updated my answer above to show this.

One last request - can you explain in plain English why Swift allows the closure to be represented by 'RecommendationErrors.StringError'?

Generally, Swift allows you to get method references as:

let methodRef = SomeType.someMethod


If the method is a static or class method, you can call the method directly using the reference. If it is an instance method, the resulting reference method is actually a curried function with the target instance passed as the first curried parameter. Swift 2.0 now allows you to reference Enumeration associated value constructors just like you can for static or class methods.

Possible to pass an enum 'type'?
 
 
Q