Well my use case is a bit challenging and has to do with the way CoreML autogenerates a class for every model and a respective series of predict methods. I have done my best to boil down the problem to its simplest form.
I have the following two classes, each contains a predict method with ALWAYS has the same input type.
class one {
func predict(input: Int) -> Double {
// Code
}
}
class two {
func predict(cool: Int) -> Int {
// Code
}
}
The following class is responsible for calling the .predict method in the above classes and a generic apply function which allows me to invoke the function without knowing the parameter name.
class Consumer<Consumed> {
let model: Consumed
init(model: Consumed) {
self.model = model
}
func anyFunction() {
apply(fn: self.model.predict, arg: 4)
}
}
// Generic Apply Method
func apply<T, V>(fn: (T) throws -> V, arg: T) -> V? {
do {
return try? fn(arg)
}
}
Obviously the code above does not compile because I am attempting to call .predict on a generic type which is not guaranteed to have such a method. I believe the only way to fix this is to write a protocol which ensures the predict method exists in the generic paramter Consumed, but I am not sure how to do that. Below is my best attempt at the protocol that I believe <Consumed: ...> should conform to.
protocol ModelProtocol {
func prediction<Input, Output>(input: Input) throws -> Output
}
Any help it appreciated, thanks!
Using a generic method as a protocol requirement may often be a mistake and you would find things would not work as you expect.
And predict(input:)
and predict(cool:)
are different methods, so you cannot define a single simple protocol.
(And they do not throws
.)
An example of defining the two classes and the protocol would be something like this:
class One {
func predict(input: Int) -> Double {
// Code
return 0
}
}
class Two {
func predict(cool: Int) -> Int {
// Code
return 0
}
}
protocol ModelProtocol {
associatedtype Input: Numeric
associatedtype Output
func prediction(input: Input) throws -> Output
}
extension One: ModelProtocol {
func prediction(input: Int) throws -> Double {
predict(input: input)
}
}
extension Two: ModelProtocol {
func prediction(input: Int) throws -> Int {
predict(cool: input)
}
}
With above prepared, you can write something like this;
class Consumer<Consumed: ModelProtocol> {
let model: Consumed
init(model: Consumed) {
self.model = model
}
func anyFunction() {
_ = apply(fn: self.model.prediction(input:), arg: 4)
}
}
// Generic Apply Method
func apply<T, V>(fn: (T) throws -> V, arg: T) -> V? {
do {
return try? fn(arg)
}
}
Or, there may be some better ways, but with your simplified classes shown, I cannot say what would be better.