2
votes

I have data wrapper class with parameter T. There is function in this class with generic container with nullable type: T? (e.g. LiveData< T?>)

class Wrapper<T> {
   fun add (data: LiveData<T?>) {
    // ...
   }
}

In this place I really need just such type. When I try to use this method and pass non-null type parameter:

class Program {
   fun get() {
      // some generic container, e.g. LiveData
      val data: LiveData<Int> = MutableLiveData()
      val wrapper = Wrapper<Int>()
      wrapper.add(data)
                  ^^^^ error
   }
}

it was 'Type mismatch' error: image link

Type mismatch: inferred type is LiveData<Int> but LiveData<Int?> was expected

How to deal with it? How smart cast generic type parameter from non-null to nullable?

2
Why you need it's parameter type to be nullable? Couldn't that be the data you're passing to add function?noiaverbale
@noiaverbale for LiveData which can return nullable values for example when using Android Room library and trying to find entity by id that does not exist, DAO method returns LiveData with null valueVitalii Musatov
In this case (if data contains nullable integers), shouldn't be data declared as val data: LiveData<Int?>? That would solve the problem immediately.DVarga

2 Answers

1
votes

That's an error related to variance: LiveData<Int?> can only be a subtype of LiveData<Int> if you make T an out variable:

class LiveData<out T>

The general rule is: when a type parameter T of a class C is declared out, it may occur only in out-position in the members of C, but in return C<Base> can safely be a supertype of C<Derived>.

In "clever words" they say that the class C is covariant in the parameter T, or that T is a covariant type parameter. You can think of C as being a producer of T's, and NOT a consumer of T's.

But it's even better to simply change the add signature to accept LiveData<T> unless this is not desired.

0
votes

You may fix the Wrapper class declaration to the following

class Wrapper<T> {
   fun add (data: LiveData<T>) {
    // ...
   }

I replaced the T? with T in the LiveData type parameter. So that you may have both Wrapper<Int> and Wrapper<Int?> types.

Kotlin tells nullable types (e.g. Int?) from non-nullable types, e.g. Int. You may check the article for more details: https://kotlinlang.org/docs/reference/null-safety.html

The second option is suggested in the previous answer to use variance. It may not be possible to use for some implementations of LiveData class/interface.
https://kotlinlang.org/docs/reference/generics.html