Scala callbacks in Kotlin

Alexey Soshin
2 min readAug 21, 2019

--

Photo by Tine Ivanič on Unsplash

Passing Scala procedures to Kotlin, and invoking them may not be as trivial as it seems.

For the past few months I’ve been working on integrating Scala and Kotlin code. In both of those JVM languages, it’s common to use higher-order functions. That is, passing a function to another function.

Sometimes, those functions may also be used as callbacks. Consider a case when you would like to invoke some Kotlin code from Scala with a resource, but release this resource from Kotlin (a borrow pattern):

// Scala
invokeKotlin("input", () => { println("Back to Scala, releasing")})

Signature of this function in Scala looks pretty innocent in Kotlin terms:

// Still Scala
def invokeKotlin(input: String, block: () => Unit) = {
new KotlinClosable(input, block)
}

So you may be tempted to specify it using the same terms in Kotlin:

data class KotlinClosable (
val input: String,
private val block: () -> Unit
) : Closeable {
override fun close() {
block()
}
}

But that code won’t compile. The reason becomes quite obvious from the error message. Scala’s Function0 is not Kotlin’s Function0 , nor Scala’s Unit is Kotlin’s Unit

Also, block doesn’t have invoke() method Kotlin expects.

Are we stuck? Not yet.

First, let’s fix the signature of our class:

private val closeBlock: scala.Function0<scala.Unit>

Here we specify, that that function we expect is actually a Scala function, that receives zero arguments and returns nothing.

Next, let’s invoke it:

block.apply()

Since it’s a Scala function, the correct way to invoke it is using apply()

In some cases, you may be tempted to define this Scala function as optional:

private val closeBlock: scala.Function0<scala.Unit>?

That’s something you shouldn’t do. You’ll get a weird error saying:

scala.runtime.BoxedUnit cannot be cast to scala.Unit

Avoid nullable callbacks from Scala to Kotlin.

Conclusions

It’s possible to pass Scala callbacks to code written in Kotlin. But you should use the correct Scala functional types, and be careful with nullability.

--

--

Alexey Soshin

Solutions Architect @Depop, author of “Kotlin Design Patterns and Best Practices” book and “Pragmatic System Design” course