1

I’m trying to do the following:

 inline fun <reified T> getMapper(klass: Class<T>): RFMFunction<T, Event> =
    when (klass) {
      MClick::class.java -> MClickMapper
      else -> { throw RuntimeException("Unknown event type: $klass") }
    }

with:

object MClickMapper : RFMFunction<MClick, Event>()

but Kotlin doesn’t recognize that MClickMapper is a subclass of RFMFunction<MClick, Event>.

I tried to add a cast as RFMFunction<MClick, Event> in the when, but that didn’t work.

The error I get is:

Type mismatch.
Required: RFMFunction<T, Event>
Found: ClickMapper

Is there a way to do that?

Thanks!

5
  • What is the exact error message? Commented Jan 31, 2023 at 16:41
  • The whole point of reified is to avoid passing a class to the function, you can directly do when(T::class). Also MClickMapper is not valid syntax. Did you mean MClickMapper()? Commented Jan 31, 2023 at 16:42
  • 1
    MClickMapper is valid syntax for a Kotlin object Commented Jan 31, 2023 at 16:43
  • @Frank Can you post the function call? Commented Jan 31, 2023 at 16:46
  • The call is just Mapper.getMapper(myKlass). Commented Jan 31, 2023 at 17:17

1 Answer 1

2

Kotlin doesn’t recognize that MClickMapper is a subclass of RFMFunction<MClick, Event>

That is not entirely correct. The error is Type mismatch: inferred type is MClickMapper but RFMFunction<T, Event> was expected.

So in fact, Kotlin refuses to consider MClickMapper as a subclass of RFMFunction<T, Event>, because T is provided by the caller of your function. The compiler doesn't go as far as knowing that klass == MClick::class.java means that T == MClick. You could technically use an unchecked cast here (since you know more than the compiler), but it should be a cast to RFMFunction<T, Event> (not RFMFunction<MClick, Event>). And then you can suppress the unchecked cast warning.

Also, as a side note, why do you use both a KClass and a reified type argument? If you reify T, you don't need the explicit KClass:

@Suppress("UNCHECKED_CAST")
inline fun <reified T> getMapper(): RFMFunction<T, Event> = when (T::class) {
    MClick::class -> MClickMapper as RFMFunction<T, Event>
    else -> throw RuntimeException("Unknown event type: ${T::class}")
}

However, this solution is not great, because you kinda hardcode twice the relationship between MClickMapper and MClick (in the when AND in the inheritance hierarchy), which means if those 2 places go out of sync you can have problems that won't be seen at compile time. It would be better to use the type information to create the mapping dynamically, so you have the mapping harcoded in a single place.

Sign up to request clarification or add additional context in comments.

2 Comments

How would you create the mapping dynamically?
That depends a bit on your overall code organization. For instance if all RFMFunction subclasses are objects, you could "register" them in a heterogeneous map. The registering function would have type parameters that would prevent mistakes and enforce consistency with the type hierarchy, and then you can safely add your unsafe cast and suppress warning on the map access.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.