3

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?

9
  • How could you have solved this using @FunctionalInterface? Kotlin does not support SAM for Kotlin-defined interfaces, regardless of how they're annotated. Commented Sep 25, 2018 at 14:05
  • I could add a Java interface which has the annotation then I can use it like this: addInputListener(InputListener{ // do something }) which is still not perfect but better than the alternative. Commented Sep 25, 2018 at 14:08
  • My current solution is an extension function which does not pollute the Java namespace but with this option I have 2 versions of 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? Commented Sep 25, 2018 at 14:10
  • 1
    Defining the API in Java interfaces and doing the implementation in Kotlin would give you sam conversion in both languages. gist.github.com/zapl/443ca6272d41db24a992c1c536d7ed45 Commented Sep 25, 2018 at 14:24
  • 1
    You can rewrite the onInput method as an extension function, then it won't be visible from Java. Commented Oct 21, 2018 at 7:33

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.