Kotlin is a wonderful programming language. After roughly 12 years of Java programming working with Kotlin felt like putting on glasses after years of squinting: there’s so much to love.

But like with every relationship, some of the quirks you only discover later in your life together. After migrating more and more Java code to Kotlin code, I noticed something rather odd and frankly a bit annoying.

It’s the way Kotlin handles functional interfaces.

Java 7: a blast from the past

Let’s go back in time to a world without lambdas. It was terribly verbose!

Java 8: Lambdas to the rescue!

Finally Java 8 gave us Lambdas and we could get rid of a lot of code and focus on what’s important. Also we weren’t forced to write our own functional interface for every simple function we could just use some that oracle provided such as: java.util.function.Function<T, R>

Things were nice until you realised that even though you now had function types they still weren’t first-class citizen in the language. Want proof? Guess how many “Types of Functions” had to be introduced in Java? One? Three? Five?

43!

Don’t believe me, see for yourself: https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html

And if that’s not enough for you, add jOOL to the mix and you have access to 35 more: https://github.com/jOOQ/jOOL/tree/master/jOOL/src/main/java/org/jooq/lambda/function

Because who wouldn’t love coming across a method signature that looks like this:

Function5<String, String, String, String, String, Tuple3<String, String, String>> higherOrder(Function12<String, Integer, String, Object, Object, Object, BiFunction<String, Integer, String>, String, Integer, Long, String, Double, Optional<Tuple2<String, String>>>)

😜 side note: jOOL is actually quite a neat library, and worth checking out.

Kotlin help us!

Now let’s add Kotlin to the mix. In Kotlin functions are first-class citizen. So no need to remember dozens of slightly different function types. You just need to remember Kotlin’s Function Type Syntax:

(Parameter1Type, Parameter2Type, ParameterNType) -> ReturnType

That’s it, that’s all there’s to it.

Trouble in Paradise

So ok, why are we here, what’s the problem?

As mentioned earlier, as I migrated more and more code from Java to Kotlin. I came across some issues when working with custom functional interfaces. Because sometimes you want that additional descriptiveness.

Let’s go back to our Java 8 example

Now let’s use it from Kotlin code

delegateWork { "Print $it" }

delegateOtherWork { "Print $it" }

Nice this is great, just what we expected! Ok now let’s migrate this JavaComponent class to Kotlin. Notice we’ve changed the java.util.function.Function<Item, String> to a Kotlin function type (Item) -> String

Let’s see what happens when we use these higher order functions from Java code.

delegateWork(item -> "Print: " + item);

delegateOtherWork(item -> "Print: " + item);

Nothing out of the ordinary as expected we can use the same lambda for both methods. Let’s see what happens when we do what we’d expect in Kotlin:

delegateWork { "Print $it" } Error: Kotlin: Type mismatch: inferred type is () -> String but JavaInterface was expected

What happened? It seems the compiler can’t figure out that the signature of the lambda is the same as the functional interface method. https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions

So we have to explicitly say what we expect:

delegateWork(JavaInterface { "Print $it" })

I think this is rather disappointing but it’s not too bad. Now let’s see what happens when we also migrate the interface to Kotlin:

When we use the KotlinComponent class from Java, as expected nothing changes, the lambdas remain exactly the same. What if we use it from Kotlin code:

delegateWork { "Print $it" } Error: Kotlin: Type mismatch: inferred type is () -> String but KotlinInterface was expected

It seems the SAM conversion fails again. Now what if we just explicitly mention the Interface like we did before?

delegateWork(KotlinInterface { "Print $it" }) Error: Kotlin: Interface KotlinInterface does not have constructors

This didn’t help either. We need to create an anonymous object to make it work:

delegateWork(object : KotlinInterface {

override fun doSomething(item: Item): String {

return "Print $item"

}

})

Yikes! This feels like working with Java 7 all over again. Sadly this is because Kotlin doesn’t yet support SAM conversion for Kotlin interfaces so we have to create this anonymous object. See also: https://youtrack.jetbrains.com/issue/KT-7770

https://stackoverflow.com/a/43737962/611032

Alias time!

So how can we avoid these verbose anonymous objects and still use a custom name for the function? We use a type alias:

So now we can pass in a lambda the way we’d expect and we still have the benefit of a custom name for the function.

delegateAliasWork { "Print $it" }

So all is is well then, case closed, time to go home. Unfortunately not quite.

Lost in translation

One minor issue with type aliases is that while you can name the function type, you cannot name the method name:

val iface: JavaInterface = JavaInterface { "Print $it" }

iface.doSomething(item) val alias: KotlinFunctionalAlias = { item -> "Print $item" }

alias.invoke(item)

alias(item)

Choosing good names for the type alias and variable can mitigate the issue. Luckily we developers are great at naming things 😜

Type safety

The bigger issue is that while the type alias gives us a different name, they aren’t really different types, so we’re not actually type safe.

Let’s look at a Java example with two functional interfaces that have the same method signature.

JavaInterface1 f1 = item -> "Print " + item;

JavaInterface2 f2 = item -> "Print " + item;

f1 = f2; Error: java: incompatible types: JavaInterface2 cannot be converted to JavaInterface1

This is what we’d expect we don’t want to mix apples and oranges here.

What happens if we do the same thing with our Kotlin type aliases? (I think you know where I’m going with this)

var f1: KotlinFunctionAlias1 = { item -> "Print $item" }

var f2: KotlinFunctionAlias2 = { item -> "Print $item" }

var f3: (Item) -> String = { item -> "Print $item" }

f1 = f2

f2 = f3

f1 = f3

This works fine, the compiler doesn’t complain because like I mentioned they aren’t actually different types. They’re all simply: (Item) -> String

Solutions

So let’s quickly recap the different ways we can deal with Kotlin’s missing SAM conversion for Kotlin interfaces and their upsides and downsides

Leave functional interfaces as Java interfaces

+ Good Java interoperability

+ Support for custom method name

+ Type safe

− Need to prefix Kotlin lambda with interface name

− Additional parentheses needed

− Need to maintain Java code

Use a type alias for Kotlin function types

+ Good Java interoperability

+ Easy to use

− Not type safe

− No custom method name

Use inline classes

Another option we haven’t yet discussed is the use of the experimental Kotlin inline classes. You could “wrap” a Kotlin Function with an inline class.

inline class KotlinInlineInterface(val doSomething: (Item) -> String) fun delegateInlineWork(f: KotlinInlineInterface): String {

return f.doSomething.invoke(item)

} delegateInlineWork(KotlinInlineInterface { "Print $it" })

Even though this works, I don’t thinks it’s an appropriate way of using inline classes. Also Java interoperability isn’t currently supported: https://kotlinlang.org/docs/reference/inline-classes.html#mangling

Always use Kotlin function types

Yes you could just use (ParamT) -> ReturnT types everywhere. Often that will be sufficient but as your application grows it might get harder to read and maintain and more error-prone.

Live with anonymous objects

Of course if you don’t mind, you can just live with the anonymous objects, hope that someday Kotlin will support full SAM conversion and make use of the wonderful IDE integration to migrate your anonymous objects to lambdas

¯\_(ツ)_/¯

I’m open to criticism and would love to hear from Kotlin experts what their recommended approach is.