1

I want a generic function that can instantiate object of a few different enum types I have by supplying the enum type and the Int raw-value. These enums are also CustomStringConvertible.

I tried this:

func myFunc(type: CustomStringConvertible.Type & RawRepresentable.Type, rawValue: Int)

which results in 3 errors:

  • Non-protocol, non-class type 'CustomStringConvertible.Type' cannot be used within a protocol-constrained type
  • Non-protocol, non-class type 'RawRepresentable.Type' cannot be used within a protocol-constrained type
  • Protocol 'RawRepresentable' can only be used as a generic constraint because it has Self or associated type requirements

Forgetting about 'CustomStringConvertible` for now, I also tried:

private func myFunc<T: RawRepresentable>(rawValue: Int, skipList: [T]) {
    let thing = T.init(rawValue: rawValue)
}

But, although code completion suggests it, leads to an error about the T.init(rawValue:):

  • Cannot invoke 'init' with an argument list of type '(rawValue: Int)'

How can I form a working generic function like this?

meaning-matters
  • 21,929
  • 10
  • 82
  • 142

1 Answers1

5

The issue is that T.RawValue can be something else than Int with your current type constraints. You need to specify that T.RawValue == Int in order to pass your rawValue: Int input parameter to init(rawValue:).

func myFunc<T: RawRepresentable & CustomStringConvertible>(rawValue: Int, skipList: [T]) where T.RawValue == Int {
    let thing = T.init(rawValue: rawValue)
}
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
  • 1
    Yes, just what I was about to suggest. This is a good example of how to confuse yourself with names; it looks like the raw representable raw value is resolved, but no, that is a different raw value. :) – matt Mar 27 '20 at 10:32
  • Thanks, how will I now add `CustomStringConvertible` to the mix? – meaning-matters Mar 27 '20 at 11:01
  • @matt I agree, it's confusing. No worries in my real code it has a proper/context-specific name. – meaning-matters Mar 27 '20 at 11:02
  • @meaning-matters check my updated answer, you simply need to use the `&` operator to require the generic type to conform to several protocols. – Dávid Pásztor Mar 27 '20 at 11:04
  • @DávidPásztor Great. Still wondering why `func myFunc(type: CustomStringConvertible.Type & RawRepresentable.Type,` didn't work? – meaning-matters Mar 27 '20 at 11:22
  • 1
    @meaning-matters because `RawRepresentable.Type` is the meta-type. However, you need concrete types, since you are passing in instance, not types, so you simply need `RawRepresentable`. – Dávid Pásztor Mar 27 '20 at 11:24