I'm working on a multiplatform project and I'm trying to expose an API to add listeners:
interface InputEmitter { fun addInputListener(listener: InputListener) } InputListener is a SAM interface and it looks like this:
interface InputListener { fun onInput(input: Input) } My problem is that this works properly from both Java and Kotlin but on the Kotlin side this is not idiomatic, since I have to invoke it like this:
obj.addInputListener(object : InputListener { override fun onInput(input: Input) { TODO("not implemented") } }) instead of this:
obj.addInputListener { TODO("not implemented") } In this case the compiler complains about Type mismatch which is ok.
I could have solved this by using the @FunctionalInterface annotation and in that case the Kotlin side would be better but since this is a multiplatform project I can't use that annotation.
Adding two functions:
fun addInputListener(listener: InputListener) fun addInputListener(listener: (Input) -> Unit) is not working either because it is ambiguous from the Java side. How can I solve this problem so that it works idiomatically from both Java and Kotlin?
I know that I can do something like this:
fun addInputListener(listener: InputListener) fun onInput(listener: (Input) -> Unit) but in that case the Java user will be puzzled when he/she wants to use the onInput variant (because it resolves to Function1 which is not instantiable from the Java side).
Is there a canonical solution for this problem?
@FunctionalInterface? Kotlin does not support SAM for Kotlin-defined interfaces, regardless of how they're annotated.interfacewhich has the annotation then I can use it like this:addInputListener(InputListener{ // do something })which is still not perfect but better than the alternative.addInputListener: one which is what you see above, and the other which is an extension function and takes a lambda. Is there a better solution?