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?
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)
}