Lenny T
Lenny T

Reputation: 409

syntax for generic-parameterized variable/constant

I'm trying to create a Map that contains generic-parameterized types. For example:

abstract class Foo {
 companion object {
  val fooInjectors = HashMap<Class<T: Foo>, Injector<T: Foo>>()
 }
}

The idea is to have fooInjectors (which would be static in Java or in a companion object in Kotlin) contain a cache of sub-classes of Foo and their corresponding Injector.

Unfortunately, I can't get this to compile. I'd very much appreciate it if someone would help me figure out the syntax for this!

Upvotes: 1

Views: 220

Answers (1)

Laksitha Ranasingha
Laksitha Ranasingha

Reputation: 4507

As far as I know, you are trying to do something that is impossible in Kotlin. The companion object is a singleton and it doesn't make sense to generify a singleton as there will not be any further objects created hence generic types are irrelevant. So you can't generify the property you declared because it's in the companion object.

However, one way you could make this working is using a backing function. This backing function should annotate with declaration-site variance.

This simply means we tell the compiler that we only return a type T from the method (and don't consume). That allows us to use subtypes and the supertype of the T if required. This is called covariance.

You can look at the docs to understand it further - https://kotlinlang.org/docs/reference/generics.html#declaration-site-variance

Here's what I meant.

interface Injector<T>
class InjectorImpl<T> : Injector<T>

abstract class Foo {
    companion object {
        val fooInjectors = createMap<Foo>()

        private fun <T> createMap(): HashMap<Class<out T>, Injector<out T>> {
            return HashMap()
        }
    }
}

class Bar: Foo()

object Runner {
    @JvmStatic
    fun main(args: Array<String>) {
        Foo.fooInjectors[Bar::class.java] = InjectorImpl<Bar>()
        Foo.fooInjectors[Foo::class.java] = InjectorImpl<Bar>()
    }
}

Upvotes: 2

Related Questions