Kotlin use the same syntax as Java for Generics but generics behave a bit different. In Kotlin all generics type parameters must be specified (it does not default to “*”, even though Kotlin does have a “*” wildcard). Generics are invariant in Kotlin (like Java), making this assignment not allowed
val stringSet : HashSet<String>()
stringSet.add("a")
stringSet.add("b")
var anySet : Set<Any> = stringSet //Not allowed
This is for a good reason, type-safety. If the above assignment was allowed, getting values from anySet would work fine because String is Any. However when values are added into anySet we run into trouble.
anySet.add(Date())
var totalLength = 0;
for( str in stringSet ) {
totalLength += str.length;
//This will fail when date is reached
}
However there are times where you know you will be just pulling values out of an object, for those cases Kotlin uses the out modifier.
fun printAll(set : Set<out Any>) {
for( item in anySet ) {
//item is Any
println(item);
}
}
printAll(stringSet)
Kotlin distinguishes between generic types passed into functions and generic types returned from functions (in/out modifiers). When you specify the generic type as out, all functions which reference that generic as an input parameter will be unavailable.
val anyOutSet : Set<out Any> = stringSet
anyOutSet.add(Date()); //will not compile
Now back to the “*” wildcard.
Java
Set<*> => Set<Object>
Kotlin
Set<*> => Set<out Any?>
Java Set<Object> is similar to Set<out Any?> in Kotlin however it is not the same. As we know out generics limit the use to only functions which do not take the generic type as a parameter. Due to Kotlins enhanced type-safety there are times we have to think through the uses case a bit more than in Java.