I learn kotlin generics but naming makes me crazy.
Let consider 2 code snippets in java and in Kotlin which do the same job:
1. java
public void copy(List<? extends Number> from, List<? super Number> to) {
assert from.size() == to.size();
for (int i = 0; i < from.size(); ++i) {
to.add(from.get(i));
}
}
Everything is clear.
from
is a list of items of type which inherits from Number. So it could be List<Double>
List <Short>
etc. I understand why extends word is used
to
is a list of items of type which is a supertype of Number
. So it could List<Number>
or List<Serializable>
or List<Object>
2.Kotlin
The similar code for Kotlin:
fun copy(from: Array<out Number>, to: Array<in Number>) {
assert(from.size == to.size)
for (i in from.indices)
to[i] = from[i]
}
From my point of view it looks counterintuitive.
Why Array<out Number>
is Array of subtypes of Number ?
Why Array<in Number>
is Array of supertypes of Number ?
I am sure creaters had some logic and I want to understand it.
Array<out Number>
is an array you can get Number
s out of.
Array<in Number>
is an array you can put Number
s in to.
This is the core of how you should be thinking about it, and specifically why those names make sense. For what exactly the relevant types are -- when you think about "what sort of array can I get Number
s out of, you will notice that you can certainly get Number
s out of an Array<Int>
or an Array<Double>
, and conclude that any type that extends Number
is a valid type argument for Array<out Number>
. Additionally, you can certainly put any Number
into an Array<Object>
, and deduce that an Array<in Number>
is an Array<T>
where T
is some supertype of Number
.
In general, however, Kotlin just switches from "what could this type be?" which List<? extends Number>
makes clearer, to "what can I do with this type?" which MutableList<in Number>
makes clearer.