In Kotlin, when I have a non-public member and an inline fun
that calls it, there's a compilation error saying:
Error:(22, 25) Kotlin: Public-API inline function cannot access non-public-API
private fun f(): Unit
defined incom.example
I found several ways to call my function inside a public inline fun
, but which is the best way to do it?
Suppose I have a private fun f() { }
. Then the options I found are:
fun f() { }
Just make it public. This is the baseline solution, but if the others turn out to have major disadvantages, this can end up the best one.
@PublishedApi internal fun f() { }
Introduced in Kotlin 1.1-M04, the annotation can be applied to an internal member, making it effectively public. The implication I noticed is that any library user will still be able to call it from Java code, that's what I don't like about it.
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE") inline fun g() { f() }
Found in the stdlib sources, this annotation seems to suppress the error when applied to the calling function. But what are its limitations? Can it only be used for
inline
functions? Will the resulting program fail under some circumstances? I tried to call a non-inline function from an inline one with this trick, and it worked, but it looks suspicious.@JvmSynthetic @PublishedApi internal fun f() { }
Combine the second solution with the synthetic flag in the bytecode. I'm not sure if this is a correct usage of
@JvmSynthetic
, but this appears to hide the function from Java code, which solves the problem of the@PublishedApi internal
.
So, which of these solutions is the best way call a non-public function from a public inline one? What are the downsides of each solution that I don't see?
CodePudding user response:
@PublishedApi internal
is the intended way of exposing non-public API for use in public inline functions.
That @PublishedApi internal
member becomes effectively public and its name doesn't get mangled (if you noticed the opposite, please file a bug).
@Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE")
is a band-aid workaround in the lack of @PublishedApi
based on suppressing an error and therefore isn't recommended. With the introduction of @PublishedApi
this suppression is going to be cleaned from the standard library.
@JvmSynthetic
combined with @PublishedApi
is an interesting approach, however it can cause some problems while debugging, though I'm not sure.