Reputation: 85
I have a protocol:
protocol Model {}
And structs using this protocol:
struct Foo: Model {}
Then I have a different protocol with a generic:
protocol Controller {
func fun<T: Model>() -> Observable<T>
}
The controller's implementation of the method can infer the type:
class Bar: Controller {
func fun<Foo>() -> Observable<Foo> {
// return an observable
}
}
What I thought I was doing here was have two 'base' protocols, one for models and one for controllers. The base controller dictates a method to implement using a generic of the base model group, the implementation can then specify which model to use. After writing all that it compiles fine and everything seems in order, but when I make an instance of Bar
and try to call fun()
on it I get an error saying Generic parameter 'Foo' can not be inferred
.
Here's a minimum complete example to reproduce with:
protocol Model {}
struct Foo: Model {}
protocol Controller {
func fun<T: Model>() -> Observable<T>
}
class Bar: Controller {
func fun<Foo>() -> Observable<Foo> {
return Observable.create { observer in
let cancel = Disposables.create {
// clean up
}
return cancel
}
}
}
Calling Bar().fun()
will now give the error: Generic parameter 'Foo' can not be inferred
There are two things I don't understand here. The first is how can it know that I call the implementation that specified Foo while at the same time not being able to infer the type? Foo is not a generic, it's the actual type of the Foo struct. The second thing I don't understand and the actual question here, is if I call a method on an instance that implemented and specified a generic method, why can it not infer the type?
Upvotes: 1
Views: 59
Reputation: 270790
I think your misunderstanding is mistaking the Foo
in this method as the Foo
struct:
func fun<Foo>() -> Observable<Foo> {
// return an observable
}
It's not! Foo
in the context of the above method is just another generic type parameter!
What you are trying to achieve here...
The base controller dictates a method to implement using a generic of the base model group, the implementation can then specify which model to use.
...should be done with associated types:
protocol Model {}
struct Foo: Model {}
protocol Controller {
associatedtype ModelType: Model
func fun() -> Observable<ModelType>
}
class Bar: Controller {
typealias ModelType = Foo
func fun() -> Observable<Foo> {
return Observable.create { observer in
let cancel = Disposables.create {
// clean up
}
return cancel
}
}
}
Upvotes: 1
Reputation: 1216
First, you'll need to fix the implementation of the fun
method:
class Bar: Controller {
func fun<T: Model>() -> Observable<T> {
return Observable<T>.create { observer in
let cancel = Disposables.create {
// clean up
}
return cancel
}
}
}
Then, you'll need to infer the generic Foo
parameter within the caller like:
let observableFoo: Observable<Foo> = Bar().fun()
Upvotes: 0
Reputation: 517
func fun<Foo>(_ type: Foo.Type) -> Observable<Foo> {
return Observable.create { observer in
let cancel = Disposables.create {
// clean up
}
return cancel
}
}
Then you can call it with:
Bar.fun(YourModel.self)
Upvotes: 0