Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing kotlin extension function receiver JVM name

This is a general question. Let's say I have an extension function written in kotlin which converts DP to PX and return a NonNull Int

fun Int.toPx() {  /** implementation */ }

The function in java will look something like this

public int toPx(int $receiver) {  /** implementation */ }

In my opinion the $receiver makes the Java-interop feels generated and uninviting.

I know that you can use the @JvmName annotation with some combinations like @file:JvmName to change the name in java.

When i'm trying to use @JvmName with the receiver site target it says

"This annotation is not applicable to target type usage and use site target @receiver"

Is there a way to overcome that and change the name of the receiver and if not what is the best alternative.

like image 613
Gil Goldzweig Avatar asked Dec 12 '17 15:12

Gil Goldzweig


1 Answers

@JvmName can only be applied to functions, property accessors and top-level package facades for files. Parameter names are not supported.

Basically, you can define two functions, one taking a simple parameter and another one with receiver:

fun toPx(value: Int) { /* implementation */ }

fun Int.toPx() = toPx(this)

But, expectedly enough, this won't compile because the two functions would have the same JVM signatures. So, to disambiguate them, add @JvmName("...") to the extension and (optionally) mark the extension as inline:

fun toPx(value: Int) { /* implementation */ }

@JvmName("toPxExtension") @Suppress("nothing_to_inline")
inline fun Int.toPx() = toPx(this)

To hide the extension function from Java, you can also annotate it with @JvmSynthetic.

The downside of this solution is the top-level function toPx leaking into the IDE completion scope of the files that see the package.

like image 190
hotkey Avatar answered Sep 30 '22 06:09

hotkey