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?
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.
"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.
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.
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?> .
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)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With