Kotlin Generics

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.

Reflection of Kotlin

I have been using Kotlin now for about 2 weeks to build our new DynamoDB Driver and have come up with some notes on using Kotlin with the standard Java Reflections system.

  • Class Literal: String.class -> javaClass<String>()
  • Class Handle: “abc”.class -> “abc”.javaClass
  • Array Expansion to Varargs: constructor.newInstance(args) -> constructor.newInstance(*args)

That is it, java reflections appear to work fine