I am trying to understand this function:
public inline fun <T, R, C : MutableCollection<in R>> Array<out T>.flatMapTo(destination: C, transform: (T) -> Iterable<R>): C {
for (element in this) {
val list = transform(element)
destination.addAll(list)
}
return destination
}
if I swap in
with out
in MutableCollection<in R>
, destination.addAll(list)
stops working. The error is that addAll
expected nothing.
Why doesn't it work? Clearly, list
is an Iterable<R>
, not an object of type R
.
For example,
val list = listOf("abc")
list.flatMap{it.toList()}
As I see it, Iterable<R>
is a list of "abc"
and not "abc" itself. I mean the list of "abc" is not R
, but the whole Iterable<R>
. then why does out
stops the code from working?
CodePudding user response:
Out projected types can not use methods that consume an object of generic type
That is how out projected types work. when you write C : MutableCollection<out R>
, this means C
is a producer of R
's, or in other words C
is sub-type of a MutableCollection
which can only have methods that produce R
and it can not support any methods that consume R
or any other generic type with type argument R
.
since destination
is of type C
, you get the error saying Nothing
was expected, signifying that consumer methods of this collection are not accessible.
using in
makes it a consumer of R
's and hence you are able to use addAll
, which is a consumer method in R
.