Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin reified type parameter doesn't smart cast

I was experimenting with setting uninitialized values and was trying to get the following to work. This is mostly a curiosity in the power (and limitations) of reified generics.

I was attempting to provide default values for optional parameters of data classes.

inline fun <reified T> uninitialized(): T = when (T::class) {
  Long::class -> -1L // Type mismatch. Required: T  Found: Long
  String::class -> "" // Type mismatch. Required: T  Found: String
  // and so on...
  else -> throw UnsupportedOperationException("No uninitialized value defined for " + T::class)
}

data class Thing(
    var id: Long = uninitialized(),
    var name: String = uninitialized() // and so on...
)

When when includes is Type clauses, Kotlin has smart casting. In this example, smart casting isn't kicking in so this will not compile.

Any ideas to accomplish something similar?

like image 734
Jason Dunkelberger Avatar asked Aug 09 '16 19:08

Jason Dunkelberger


People also ask

Can use T as reified type parameter?

Cannot use 'T' as reified type parameter. Use a class instead. The possible way to access the type of the Template class is by passing it as a parameter. Since we can not use the type of template at runtime directly, we need to use reified here.

What is reified in Kotlin?

"reified" is a special type of keyword that helps Kotlin developers to access the information related to a class at runtime. "reified" can only be used with inline functions. When "reified" keyword is used, the compiler copies the function's bytecode to every section of the code where the function has been called.

What is type parameter in Kotlin?

The type parameter lets you specify exactly that—instead of “This variable holds a list,” you can say something like “This variable holds a list of strings.” Kotlin's syntax for saying “a list of strings” looks the same as in Java: List<String> . You can also declare multiple type parameters for a class.

How do I use generic Kotlin?

If a generic type has several type parameters, each of them can be projected independently. For example, if the type is declared as interface Function<in T, out U> you could use the following star-projections: Function<*, String> means Function<in Nothing, String> . Function<Int, *> means Function<Int, out Any?> .


1 Answers

A smart cast is applied to a specific object after you use is to check its type or compare it with null. In your example, there is no specific object for which you check the type, and nothing to apply the smart cast to.

However, you can apply manual casts to T, which will work as expected. Here's a working version of your sample function, updated to handle the peculiarities of Kotlin's reflection library which will be fixed in 1.1:

inline fun <reified T : Any> uninitialized(): T = when (T::class.java) {
  Long::class.javaPrimitiveType, Long::class.javaObjectType -> -1L as T      
  String::class.java -> "" as T
  // and so on...
  else -> throw UnsupportedOperationException("No uninitialized value defined for " + T::class)
}

data class Thing(
    var id: Long = uninitialized(),
    var name: String = uninitialized() // and so on...
)

fun main(args: Array<String>) {
    val t = Thing()
    println(t.id)
}
like image 115
yole Avatar answered Sep 19 '22 23:09

yole