Reputation: 353
Could someone please help me to wrap my head around the Kotlin compiler behavior?
The intention of the program is to convert the input string to a corresponding type(BMsg
or CMsg
)
and print the result in a console.
However, I receive the following message from the compiler:
"Type inference failed. Not enough information to infer parameter T ..."
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
abstract class classA<T> {
fun handle(body: String) {
val result = convertToSpecificMessageType(body) // This line fails
printResult(result)
otherImportantStuff()
}
abstract fun otherImportantStuff()
private inline fun <reified T : Any> String.toPayloadObject(): T =
jacksonObjectMapper().readValue(this, T::class.java)
private inline fun <reified T : Any> convertToSpecificMessageType(body: String): T = body.toPayloadObject()
private fun printResult(result: T) = println("result = $result")
}
class classB : classA<BMsg>() {
override fun otherImportantStuff() = print("important stuff of class B")
}
class classC : classA<CMsg>() {
override fun otherImportantStuff() = print("important stuff of class C")
}
sealed class Msg
data class BMsg(val x: String) : Msg()
data class CMsg(val y: Int) : Msg()
fun main() {
classB().handle("{\"x\" : \"aaa\"}")
classC().handle("{\"y\" : 5}")
}
Despite I found a workaround - declaring convertToSpecificMessageType
method as an abstract
and override in classB
/classC
, I'm wondering (1) what is the reason which makes the compiler to complain
(2) if there is a way to fix the problem without overriding convertToSpecificMessageType
?
Thank you in advance!
P.S. kotlin version = '1.3.21'
Upvotes: 1
Views: 1986
Reputation: 31279
By declaring <reified T : Any>
in front of your methods (toPayloadObject
and convertToSpecificMessageType
) you're introducing a new type parameter T
for your methods that has no relation to the type parameter of classA
with the same name T
.
The method-local declaration of T
shadows the T
on classA
.
As a result, when you do val result = convertToSpecificMessageType(body)
- there is no context at all that Kotlin can use to infer the type from. Although you're in a method in classA
, the T
from classA is not used by method convertToSpecificMessageType
.
The solution?
You can't use a reified type on a class so either:
<reified T : Any>
parts and pass a class object to the methodsval result = convertToSpecificMessageType<MyType>(body)
or val result : MyType = convertToSpecificMessageType(body)
Upvotes: 1