Search code examples
functionkotlinreflectionoverloading

Referencing overloaded top-level Kotlin functions reflectively


In brief, how can one reference / iterate reflectively over overloaded top-level functions in Kotlin, such as kotlin.io.println?


Given the following:

object Bar {
    fun foo(x: Int) = Unit
    fun foo(x: Byte) = Unit
    fun foo(x: Float) = Unit
}

I can iterate over the various overloads of foo by doing:

fun main() {
    Bar::class.memberFunctions
        .filter { kFunction -> kFunction.name == "foo" }
        .forEach { kFunction -> println(kFunction) }
}

Which produces:

fun com.example.Bar.foo(kotlin.Byte): kotlin.Unit
fun com.example.Bar.foo(kotlin.Float): kotlin.Unit
fun com.example.Bar.foo(kotlin.Int): kotlin.Unit

However, if the various overloads of foo are defined top-level (outside of a class or object definition) such as simply:

fun foo(x: Int) = Unit
fun foo(x: Byte) = Unit
fun foo(x: Float) = Unit

Then there doesn't seem to be a way to reference them.

I tried being tricky using a top-level function in my example (such as main) to access the synthetic class:

::main::class.memberFunctions
    .filter { kFunction -> kFunction.name == "foo" }
    .forEach { kFunction -> println(kFunction) }

But it pukes on the fact that it's synthetic:

Exception in thread "main" java.lang.UnsupportedOperationException: This class is an internal synthetic class generated by the Kotlin compiler, such as an anonymous class for a lambda, a SAM wrapper, a callable reference, etc. It's not a Kotlin class or interface, so the reflection library has no idea what declarations does it have. Please use Java reflection to inspect this class.

How can I reference top-level overloaded functions in Kotlin?

More specifically, top-level overloaded functions defined in other packages / modules such as kotlin.io.println?


Solution

  • Top level functions by definition don't have a declaring class.

    ::println.javaClass.declaringClass //will return null
    

    so you don't have a class to use reflection on, and consequently, you can't enumerate the top level members of a package.(Some magic can be done though, if you are willing to trade your soul)

    The only way you can reference ambiguous top level functions is by helping the compiler to resolve the ambiguity like this:

    val functionReference: (Int)->Unit = ::foo
    

    and then you can call functionReference()