Generic variance: can't use var with <out T> and can't use val with <in T>?

I have started to understand these covariant and contravariant relationships a bit better with continued online reading. Especially after reading these “guides”:

These guides illustrate the type/subtype relationship with variance. However, they don’t give real life code examples other than use of functions defined in the generic class, so I’m not certain how one would utilize these type/subtype relationships in code otherwise. Would that be done via casting?

You mention “downcasting” and “casting” and I’m now trying to take the type/subtype relationships I am understanding and apply them to casting, but I’m not getting there.

In the code example you provided above:

class Container<in T>(val content: T) //Compiler error right here

fun main() {
    val cont = Container<Any>(Any()) // Just creating a new Any object for this example
    val contString: Container<String> = cont //This is totally legal because in guarantees downcasting safely
    val str: String = contString.content //Whoops, you are now trying to cast an Any to a String.
}

We have setup a simple generic class. We can create objects of that class with an Any type or a String type, or any other type.
We create an object of type Container<Any>, and reference it with the val cont.
It looks like we then cast that object as a type Container<String> and reference that with a different val contString. Is there a type/subtype relationship here?

1 Like