Reputation: 31
I don't know how to specify a function literal where the input parameter can covary so that the function literal can have assigned to it functions that accept subtypes of the input type.
The simplest example I can come up with is that i want to do something like this:
var f: (Number) -> Unit = { number: Number -> println(number) }
f = {int: Int -> println(number) } // <-- this does not compile
These declarations do not work:
var f: (in Number) -> Unit = {number: Number ->} // doesn't compile
var f: (out Number) -> Unit = {number: Number ->} // doesn't compile
var f: <N: Number> (N) -> Unit = {number: Number ->} // ridiculous
Here is the context of what I ACTUALLY want to do. I want to create a simple event handler class.
This is my Kotlin code:
class EventHandler() {
private val NO_OP = {event: Event -> }
private val handlerMap =
mutableMapOf<KClass<out Event>, (Event) -> Unit>() // here is the problem declaration
fun <E: Event> registerHandler(
eventClass: KClass<out E>,
handler: (E) -> Unit) {
handlerMap[eventClass] = handler // this doesn't compile
}
fun handle(event: Event) = getHandler(event).invoke(event)
fun getHandler(event: Event): (Event) -> Unit =
handlerMap[event::class] ?: NO_OP
}
The handlerMap[eventClass] = handler
doesn't compile, because the handlerMap
accepts as values (Event) -> Unit
, and the type of the handler
is (E) -> Unit
where E
is a type parameter that extends Event (<E: Event>
).
The Error message is:
Events.kt:[18,9] Type inference failed: Cannot infer type parameter V in operator inline fun <K, V> MutableMap<K, V>.set(key: K, value: V): Unit
None of the following substitutions
receiver: MutableMap<KClass<out Event>, (Event) -> Unit> arguments: (KClass<out Event>,(Event) -> Unit)
receiver: MutableMap<KClass<out Event>, (E) -> Unit> arguments: (KClass<out Event>,(E) -> Unit)
can be applied to
receiver: MutableMap<KClass<out Event>, (Event) -> Unit> arguments: (KClass<out E>,(E) -> Unit)
I am using kotlin-maven-plugin:1.1-M03.
Upvotes: 0
Views: 455
Reputation: 31
Ok, I didn't think of this before, but it looks like you can just cast the Function to the type of the literal.
In other words, you can do this
var f: (Number) -> Unit = { number: Number -> println(number) }
f = {int: Int -> println(number) } as (Number) -> Unit
For my actual usecase, I would make the registerHandler
function look like this:
fun <E: Event> registerHandler(eventClass: KClass<out E>, handler: (E) -> Unit) {
handlerMap[eventClass] = handler as (Event) -> Unit
}
Upvotes: 1