How to declarate a generic Key-Value variable with class types as key?

Hi guys,

I tried to figure this out for myself for some time now, but I just cant find out how to do it:

I want something like this:

private val components : Map<KClass<T : IComponent>, List<T>>

Or in words: components shall be a MAP with KEYS:
Class Type of classes that inherit from IComponent, VALUES: Arrays of
objects of the type of the KEY

To use it in this code:

class GameObject
{
    val components : ObjectMap<KClass<out IComponent>, Array<*>> = ObjectMap()

    fun update(deltaTime: Float)
    {
        for(componentFamily in components.values())
        {
            for(component in componentFamily)
            {
                component.update(deltaTime)
            }
        }
    }

    inline fun <reified T : IComponent> get() : T?
    {
        return components.get(T::class)[0] // This does not work - it returns Any?, not T?
    }
}

Please help. Thank you for having a look.

On StackOverflow someone recommended to use:

list.filterIsInstance<T>()

which simplifies my code to:

class GameObject
{
    val components = List<IComponent>(0) {}

    fun update(deltaTime: Float)
    {
        for(component in components) { component.update(deltaTime) }
    }

    inline fun <reified T : IComponent> get() : T?
    {
        return components.filterIsInstance<T>().first()
    }
}

This does indeed work. But still: is it possible to achieve, what I tried?

The two variations of components you give are not quite the same. The first (separate) variant doesn’t quite work as you expect as T is resolved for the full map, not for each element of the map. The correct version of this would be:

   private val components: Map<KClass<out IComponent>,List<IComponent>>

As such it means that you cannot have a typesafe list of components. But you can encapsulate the type safety inside a wrapper (such as GameObject) to have servicable code with a cast in the get function. It may be possible to do some complicated things with wrappers etc to actually have a typesafe list of elements, but frankly going with a few casts and carefully written code is a better, likely more performant (no useless intermediates or recursive searches etc.), less complex, solution. You just have to make sure that components are only added to the correct list, but if you encapsulate it, that is not too hard.

Thank you.