While reading about Kotlin generics type variance and projection I came up with completely unfamiliar concept to me. Can someone explain please what is the idea that the author wants to explain? Please this quote from Kotlin in Action, MEAP:
There is no sense to get anoutprojection of a type parameter that already hasoutvariance, such asList<out T>. That would mean the same asList<T>, becauseListis declared asclass List<out T>. The Kotlin compiler will warn that such a projection is redundant.
There are two concrete questions here:
As quoted, it would be “redundant”, thus you’d never want to do that. It simply does not add any benefit. The whole quote is related to use-site variance, i.e. variance specified by the client (corresponds to wildcards in Java). The class List<out T> already has a declaration-site variance modifier out, which makes the use-site application of out redundant.
Here's an example of redundant client-site variance:
fun <T> useList(list: List<out T>) {
println("first element: ${list[0]}")
}
I applied the out modifier to a function parameter of type List<T>, this is an example of use-site variance. It is redundant which the compiler notices: "Projection is redundant". It does not make it worse nor any better.
On the other hand, if you're using a type that is not projected on declaration-site already, it does make sense. For example, the Array class is not restricted in its variance: public class Array<T>.
Rewriting the former example to use Array, it suddenly makes sense to add an out modifier, since the parameter is only used as a producer of T, i.e. not in in position.
Example of meaningful client-site variance:
fun <T> useArray(arr: Array<out T>) {
println("first element: ${arr[0]}")
}
As a rule of thumb, corresponding to Java‘s PECS (Producer extends, Consumer super), you can memorize POCI for Kotlin (Producer out, Consumer in).
- Why you ever need to add out projection on already out projected type List?
You don't, but it may happen by accident, such as through refactoring or in a deep call chain where you lose sight of the generic parameters being passed around.
- Even if you do so, how you get the same List?
In an analogy, you might consider the projection as an idempotent transform: out out T is the same as just out T.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With