Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin - Cannot use 'T' as reified type parameter. Use a class instead

I have a simple helper function to get value from SharedPreferences like this :

operator inline fun <reified T : Any> SharedPreferences.get(key: String, defaultValue: T? = null): T? {
    return when (T::class) {
        String::class -> getString(key, defaultValue as? String) as T?
        Int::class -> getInt(key, defaultValue as? Int ?: -1) as T?
        Boolean::class -> getBoolean(key, defaultValue as? Boolean ?: false) as T?
        Float::class -> getFloat(key, defaultValue as? Float ?: -1f) as T?
        Long::class -> getLong(key, defaultValue as? Long ?: -1) as T?
        else -> throw UnsupportedOperationException("Not yet implemented")
    }
}

I have used reified type parameter to have switching over class type and since it is an operator function, I should be able to call with the square brackets syntax like below :

val name: String? = prefs[Constants.PREF_NAME]

But, every time I call it, UnsupportedOperationException is thrown indicating function is not able to get class type.

When I attach debugger and evaluate T::class, It is giving me an error "Cannot use 'T' as reified type parameter. Use a class instead."

What's wrong with my function? I could not catch the mistake. can anyone help?

Edit : The whole class is here and this is where I get the error.

Update: It seems to be Kotlin compiler issue. Track https://youtrack.jetbrains.com/issue/KT-17748 and https://youtrack.jetbrains.com/issue/KT-17748 for updates.

like image 804
Krupal Shah Avatar asked Jun 17 '17 09:06

Krupal Shah


People also ask

What is reified type parameter in Kotlin?

Reified Generics in Kotlin Generics on the JVM are normally implemented through type erasure, meaning generic type arguments of a function is not preserved at runtime. To solve this, Kotlin may use a reified type parameter that can only be used with inline functions.

How to find the type of a class in Kotlin?

To access the information about the type of class, we use a keyword called reified in Kotlin. In order to use the reified type, we need to use the inline function. If a function is marked as inline, then wherever the function is called, the compiler will paste the whole body of the function there. Learn more about inline from here.

Why can't I access the type T in Kotlin's generic functions?

Therefore this little post is intended to bring some light into the darkness of Kotlin's reified types. In an ordinary generic function like myGenericFun, you can't access the type T because it is, like in Java, erased at runtime and thus only available at compile time.

What is an inline reified function with reified type parameter t?

Using an inline function with reified type parameter T makes it possible to implement our function as follows: There's no need to pass the Class of T additionally, T can be used as if it was an ordinary class. For the client the code looks like this: Inline reified functions are not callable from Java code, whereas normal inline functions are.


Video Answer


1 Answers

The problem is curious, but it seems that Int::class is not the same as Int?::class (which is an illegal expression any ways).

When you add the line:

println(T::class)

To the get method, and call val age: Int? = prefs["AGE", 23], you will see that it prints java.lang.Integer.

It seems like Int? is translated into java.lang.Integer.

A possible (but imho kind of hacky) solution is to use the references to Java classes as the cases for when:

operator inline fun <reified T : Any> get(key: String, defaultValue: T? = null): T? {
    return when (T::class) {
        String::class -> getString(key, defaultValue as? String) as T?
        java.lang.Integer::class -> getInt(key, defaultValue as? Int ?: -1) as T?
        java.lang.Boolean::class -> getBoolean(key, defaultValue as? Boolean ?: false) as T?
        java.lang.Float::class -> getFloat(key, defaultValue as? Float ?: -1f) as T?
        java.lang.Long::class -> getLong(key, defaultValue as? Long ?: -1) as T?
        else -> throw UnsupportedOperationException("Not yet implemented")
    }
}
like image 155
Jorn Vernee Avatar answered Sep 19 '22 11:09

Jorn Vernee