Access value by type with any kind of data structure

Suppose I need to keep three numbers of Int, Long and Float in a bunch, and access these numbers by their type.
First idea is to use HashMap, where key is type of number, and value is number itself.

val bunch = mapOf<KClass<out Number>, Number>(
    Int::class to 0,
    Long::class to 0L,
    Float::class to 0f,
)

But in this case Kotlin does not inference needed value type, and I need to use explicit cast.

val i: Int = bunch[Int::class]!! // Error: Initializer type mismatch: expected 'Int', actual 'Number'.
val f: Float = bunch[Int::class]!! as Float

Also this does not guarantee that value has the type, spcecified by the key. So I can do

val bunch = mapOf<KClass<out Number>, Number>(
    Int::class to 0L, // Long value for Int type
)

val l: Float = bunch[Int::class]!! as Float // Get Int as Float

Can you suggest more appropriate solution for the problem (access value by type with any kind of data structure)?

I made this typed Map:

private class MutableTypedMap private constructor(private val map: MutableMap<Key<*>, Any?>) {
  constructor() : this(mutableMapOf())

  interface Key<T>

  @Suppress("UNCHECKED_CAST")
  operator fun <T> get(key: Key<T>): T = map.getValue(key) as T

  operator fun <T> set(key: Key<T>, value: T) {
    map[key] = value
  }
}

You can replace Key<T> with KClass, and everything should work just fine!
Edit: Here you go!

import kotlin.reflect.*
val bunch = MutableTypedMap().apply {
    this[Int::class] = 0
    this[Long::class] = 0L
    this[Float::class] = 0f
}

fun main() {
    val i: Int = bunch[Int::class]!!
	val f: Float = bunch[Float::class]!!
    println(i)
    println(f)
}

class MutableTypedMap private constructor(private val map: MutableMap<KClass<*>, Any>) {
  constructor() : this(mutableMapOf())

  @Suppress("UNCHECKED_CAST")
  operator fun <T: Any> get(key: KClass<T>): T? = map[key] as T?

  operator fun <T: Any> set(key: KClass<T>, value: T) {
    map[key] = value
  }
}

You can also check my little library: GitHub - broo2s/typedmap: Type-safe heterogeneous map in Kotlin , although your case is a small subset of its functionality, so it may be considered an overkill. You can also read the README for alternative libraries or approaches.

// create a typed map
val sess = simpleTypedMap()

// add a User item
sess += User("alice")

// get an item of the User type
val user = sess.get<User>()

println("User: $user")
// User(username=alice)

@kyay10 @broot Guys, you are great. Thank you!

1 Like

Also look at the Kotlin coroutine code, specifically the CoroutineContext. From what I understand, it’s basically a Map that does exactly what you want; has typed Keys and Values.