3

In my simplified example I'm getting the error: Cannot convert value of type 'Foo' to expected argument type BaseItem<Any>

But the class Foo extends BaseItem<String>.

This is the example code:

class BaseItem<T> {
    var param: T?
}

class Foo: BaseItem<Int> {
}

func checkItem(item: BaseItem<Any>) -> Bool{
    return item.param  != nil;
}

I get the error when calling

checkItem(item: Foo())

What am I missing?

Hamish
  • 78,605
  • 19
  • 187
  • 280
Addev
  • 31,819
  • 51
  • 183
  • 302

4 Answers4

1

You need to define your checkItem function in terms of generics too:

func checkItem<T>(item: BaseItem<T>) -> Bool {
    return item.param != nil
 }
Paulw11
  • 108,386
  • 14
  • 159
  • 186
0

The signature of checkItem function should be: checkItem<T>(item: BaseItem<T>) -> Bool, as follows:

func checkItem<T>(item: BaseItem<T>) -> Bool {
    return item.param  != nil
}

Usage:

checkItem(item: Foo()) // false

let myFoo = Foo()
myFoo.param = 0

checkItem(item: myFoo) // true

The reason of why the compiler complains about

Cannot convert value of type 'Foo' to expected argument type BaseItem

is that you are trying to pass BaseItem<Int> instance as BaseItem<Any> which is invalid (Any data type is not T generic type).

Ahmad F
  • 30,560
  • 17
  • 97
  • 143
0

Gotta define checkItem function with generics too.

func checkItem<T>(item: BaseItem<T>) -> Bool {
     return item.param  != nil
}
Nebojsa Nadj
  • 621
  • 3
  • 12
0

The problem is that generics are invariant – consider if your checkItem(item:) function had said:

func checkItem(item: BaseItem<Any>) {
    item.param = "foo"
}

That would be illegal for a BaseItem<Int>, as you cannot possibly assign a String instance to an Int? property – which is why it (an instance of Foo) cannot be typed as a 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, rather than saying that you're taking a BaseItem<Any>, that has a param of type Any? (can be assigned a value of any type) – you're now saying that you're taking a BaseItem with any specific placeholder type; which will be satisfied at the call-site of the function.

The function implementation itself therefore cannot make any assumptions about this type, and will disallow the assignment of an arbitrary value to param. The compiler will only allow an assignment of a value of type T.

Community
  • 1
  • 1
Hamish
  • 78,605
  • 19
  • 187
  • 280