Cannot convert value type ... when using generics and polymorphism in Swift 3
In my simplified example, I get an error: Cannot convert value of type 'Foo' to expected argument type BaseItem<Any>
But the class Foo
continues BaseItem<String>
.
This is some sample code:
class BaseItem<T> {
var param: T?
}
class Foo: BaseItem<Int> {
}
func checkItem(item: BaseItem<Any>) -> Bool{
return item.param != nil;
}
I am getting an error when calling
checkItem(item: Foo())
What am I missing?
source to share
The function signature checkItem
must be:, checkItem<T>(item: BaseItem<T>) -> Bool
as follows:
func checkItem<T>(item: BaseItem<T>) -> Bool {
return item.param != nil
}
Using:
checkItem(item: Foo()) // false
let myFoo = Foo()
myFoo.param = 0
checkItem(item: myFoo) // true
The reason why the compiler is complaining about
Cannot convert value of type Foo to expected type of BaseItem argument
is that you are trying to pass an BaseItem<Int>
instance as BaseItem<Any>
, which is invalid ( Any
data type not T
generic).
source to share
The problem is that generics are invariant - consider if your function was checkItem(item:)
:
func checkItem(item: BaseItem<Any>) {
item.param = "foo"
}
This would be illegal for BaseItem<Int>
, since you cannot assign an instance String
to a property Int?
, so it (instance Foo
) cannot be injected as BaseItem<Any>
.
The solution, as other answers have said, is to use a generic placeholder for the function:
func checkItem<T>(item: BaseItem<T>) -> Bool {
return item.param != nil
}
Now, instead of saying that you are taking BaseItem<Any>
which has a param
type Any?
(it can be assigned a value of any type) - you are now saying that you are taking a BaseItem
with any particular placeholder type; which will be executed on the function call site.
The function implementation itself cannot make any assumptions about this type and does not allow assignment of an arbitrary value param
. The compiler will only allow assignment of a value to a type T
.
source to share