How to call a generic function with a parameter of a related type in Swift 3

Here's my sample code:

protocol P {

}

protocol B {

  associatedtype ID: P

}

class MyClass: B {
  enum ID: P {
    case one
    case two
  }
}

func process<T: B>(_ value: T.ID) {
  // do something
}

process(MyClass.ID.one) // Compile Error: cannot convert value of type 'MyClass.ID' to expected argument type '_.ID'

      

As you can see, I define a generic function with a parameter whose type is associated type of general type T . How can I call this function? I want to use MyClass.ID.one as an argument, but the compiler gives the following warning:

cannot convert value of type 'MyClass.ID' to expected argument type '_.ID'

      

+3


source to share


2 answers


It looks like Swift has an issue of deducting T

from a call starting with MyClass.ID

, is T.ID

, and for is MyClass

used T

.

If you change your function to take an additional type parameter T

, the code compiles and works fine:

func process<T: B>(_ value: T.ID, _ workaround : T) {
  // do something
}

let workaround = MyClass()
process(MyClass.ID.one, workaround)

      

Swift designers can approach this inference problem in two ways:

  • Correct the inference engine to resolve this use case, or
  • Simplify the inference engine for definition T

    by applying stricter rules for function signatures.


It looks like they solved the second approach with Swift 4, because the original function won't compile, throwing the following error:

generic parameter is 'T'

not used in function signature

Better work to pass a type instead of an instance using a Java style approach:

func process<T: B>(_ value: T.ID, _ workaround: T.Type) {
  // do something
}
...
process(MyClass.ID.one, MyClass.self)

      

Note. ... Editing based on very insightful tesch comments

+3


source


dasblinkenlight gives a good answer to the question of why your current implementation is not working. If the decisive resolution is simply to find another way to implement this feature, I would go for a less hacky solution:

extension B {
    static func process(_ value: Self.ID) {
        //do stuff
    }
}

MyClass.process(.one)

      



This takes advantage of the more flexible type inference achieved with a protocol extension Self

.

0


source







All Articles