I am trying to implement a function definition that accepts a generic parameter, as long as it extends another specific generic type. In short; param A must extend param B, where A and B are both generic.
My sample example below
abstract class Endpoint<T>(
) {
private val myList: MutableMap<Class<T>, MutableList<((T) -> Unit)>> = mutableMapOf()
fun addToList(
index: Class<E>, <-- E extends T
value: (E) -> Unit
) {
myList[index] = (myList[index] ?: mutableListOf()).apply { add(value) }
}
}
Usage example would be
Some sealed class
sealed class MainSealedClass {
data class ChildClass(val someParam: Int): MainSealedClass()
}
And the function call
anEndpointInstance.addToList(MainSealedClass.ChildClass::class.java, "some value")
I would like to not having to define E in the abstract class declaration, since T is already defined there.
I tried doing the following as well:
Define myList as accepting keys that extend T as such
val myList: MutableMap<Class<in T>, MutableList<String>>
Define E as a T type (couldn't find how to specify it extends T in the function
fun <E:T> addToList(
index: Class<E>,
value: (E) -> Unit
) {
myList[index] = (myList[index] ?: mutableListOf()).apply { add(value) }
}
fun addToList(
index: Class<in T>,
value: (E) -> Unit
) {
myList[index] = (myList[index] ?: mutableListOf()).apply { add(value) }
}
fun <E> addToList(
index: Class<E>,
value: (E) -> Unit
) where E : T {
myList[index] = (myList[index] ?: mutableListOf()).apply { add(value) }
}
But it never works. Is there a way of achieving this? I could not find anything in StackOverflow that had an answer for this scenario.
CodePudding user response:
You got your variance inverted. If you want your map to accept Classes of subtypes of T, then it needs to be <out T>
. If you're not inspecting the keys, you could probably just put Class<*>
.
Your first way of declaring the function was correct.
abstract class Endpoint<T>(
) {
private val myList: MutableMap<Class<out T>, MutableList<String>> = mutableMapOf()
fun <E : T> addToList(
index: Class<E>,
value: String
) {
myList.getOrPut(index, ::mutableListOf).add(value)
}
}