Home > Blockchain >  How to specify in a lambda "accepts generic sub-type of a generic type"?
How to specify in a lambda "accepts generic sub-type of a generic type"?

Time:04-19

This question is a derivative of a recent one I made here

While that one was resolved, I immediately faced a new one of a similar nature, but I am also not able to find a solution for it.

Sample example:

abstract class Endpoint<T>() {

    private val myList: MutableList<(T) -> Unit> = mutableListOf()

    fun <E : T> addToList(cbk: (E) -> Unit) { <-- E extends T
        myList.add(cbk)
    }

}

Usage example would be

Some sealed class

sealed class MainSealedClass {
    data class ChildClass(val someParam: Int): MainSealedClass()
}

And the function call

anEndpointInstance.addToList<ChildClass>{it: ChildClass -> 
    // do something here
}

I tried doing the following, but it looks like it is not is not allowed

val myList: MutableList<(out T) -> Unit> <--- Unsupported error shows up

Is there a way to do this without having to add an extra declaration at the class level?

I considered using inline reified but the function needs to access private fields of the Endpoint instance, so I do not want to use that option.

CodePudding user response:

I don't think the language supports specifying variance of the parameters of a functional type, or references to functions with generic types that aren't defined. For example, if you want to get a reference to a generic function, you have to specify its generic types in the functional type declaration.

There is dubious usefulness here anyway. If you had a list of functions that each have different input types, then when you retrieve a function from the list, you won't be able to call it because you won't know which input type it supports. You might as well have a MutableList<Any>.

CodePudding user response:

Thanks to Tenfour04's knowledge, I was able to find a workaround to my issue. I do not consider this to be a fix for my issue, but given that it apparently cannot be done as I expected, the next best thing was to work around the issue with the help of a wrapper.

Here is how my code turned out with the work using the sample in my question

abstract class Endpoint<T>() {

    private val myList: MutableList<(T) -> Unit> = mutableListOf()

    fun add(cbk: (T) -> Unit) {
        myList.add(cbk)
    }

    inline fun <reified N : T> addToList(crossinline callback: (N) -> Unit) {
        add { if (it is N) callback.invoke(it) }
    }

}

And its usage is the way I wanted in my question, nothing changes at this point.

  • Related