KMM Oddity #1: Interface methods with underscores

Yev Kanivets
xorum.io
Published in
4 min readSep 20, 2021

--

Kotlin Multiplatform attracts more and more developers every day. Especially after the technology transitioned to the Alpha stage. On its way to Beta, KMP removes all major hassles (Memory Model, for example).

Nonetheless, you can still find “a few” more minor bugs and oddities reported in Kotlin’s YouTrack. They aren’t blockers for using KMP in your production application but may cost you several hours of wondering what and why is happening in your mobile application (mainly on iOS).

I faced many such issues myself since I’ve started using Kotlin Multiplatform Mobile two years ago. In this series of articles, I’ll share my favorite oddities of KMM with explanations and workarounds (if possible).

Kotlin/Native Obj-C interop

Shared KMM modules are written in Kotlin, hence can be used in Android native applications as it is. On iOS, it’s more complicated because of Objective-C and Swift, which can’t directly use Kotlin code.

Kotlin/Native plugin compiles shared KMM modules to iOS frameworks, which contain binary and Obj-C header. You can find them in the build folder of the shared module, under bin/iOS/.

Many concepts of Kotlin don’t exist in Obj-C, so specific shortcuts and workarounds need to be applied to make it work. It is where some oddities start appearing.

Interface methods naming clash

Let’s say we have two types of pets — Dog and Cat, which we need to feed with some specific Food. In Kotlin, we could represent that with two interfaces, each having an internal (embedded) Food class.

Original commit

It works perfectly well in Android, but on iOS Dog will have eat(food_:) method instead of eat(food:). Where does that underscore suffix come from? And why do we need it?

It looks like Kotlin/Native compiler thinks there will be a clash between eat(food:) methods of Dog and Cat interfaces, so it’s safer to make them different by implicitly adding an underscore to the 2nd one.

I’m not sure it will become a problem and if it can be fixed from the Kotlin/Native side. But it becomes pretty annoying when we add a few more animals because each will have one more underscore.

A more realistic example would be about View interface in MVP architecture, where each class will have set(uiModel:) method.

Is the problem in embed classes?

So maybe it’s the embedFood class that drives K/N compiler crazy? Let’s try to extract both classes alongside pets.

Original commit

After compiling the iOS app, we see that the actual content of the Obj-C header didn’t change even a little, so the problem isn’t about embedded classes in interfaces.

What if cats and dogs share the food?

Well, that’s not a great idea, but let’s try to be sure.

Original commit

Surprisingly, it solves the issue. So if methods share the same arguments, the K/N compiler handles them as we expect. But sharing food between dogs and cats may be dangerous, so let’s try finding another solution.

Is the problem in interfaces?

Let’s try converting interfaces to abstract classes.

Original commit

And yes, both eat(food:) methods in Cat and Dog are named as expected. It seems to be a much better way to solve the issue.

Changing abstract classes to just classes is an option as well.

Conclusions

The next time you see some unexpected trailing underscores in your KMM interface method names, you can be sure that it’s not critical, and there are multiple workarounds to resolve the issue quickly.

There is an obvious solution, which wasn’t interesting enough to describe in the article itself, but which you may consider too — rename clashing methods or arguments to calm down the K/N compiler.

Resources

--

--

Yev Kanivets
xorum.io

Technical Lead Mobile @ 360Learning | KMP enthusiast | Husband & dad | Marathon finisher