Dynamically invoke Function<R>

I’m building a utility to translate lambdas into callable references inside a different language context. Essentially, making Kotlin lambdas callable from a V8 runtime living in the JVM. I have a method that takes a Function and I would like to invoke it. From what I’m understanding, it looks like I have to do something like this in order to support any lambda:

fun <R> Function<R>.call(vararg args: Any?): R = when (args.size) {
    0 -> (this as Function0<R>).invoke()
    1 -> (this as Function1<Any?, R>).invoke(args[0])
    2 -> (this as Function2<Any?, Any?, R>).invoke(args[0], args[1])
    3 -> (this as Function3<Any?, Any?, Any?, R>).invoke(args[0], args[1], args[2])
    4 -> (this as Function4<Any?, Any?, Any?, Any?, R>).invoke(args[0], args[1], args[2], args[3])
    5 -> (this as Function5<Any?, Any?, Any?, Any?, Any?, R>).invoke(args[0], args[1], args[2], args[3], args[4])
    6 -> (this as Function6<Any?, Any?, Any?, Any?, Any?, Any?, R>).invoke(args[0], args[1], args[2], args[3], args[4], args[5])
    7 -> (this as Function7<Any?, Any?, Any?, Any?, Any?, Any?, Any?, R>).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6])
    8 -> (this as Function8<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, R>).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7])
    9 -> (this as Function9<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, R>).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8])
    10 -> (this as Function10<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, R>).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9])
    11 -> (this as Function11<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, R>).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10])
    12 -> (this as Function12<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, R>).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11])
    13 -> (this as Function13<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, R>).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12])
    14 -> (this as Function14<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, R>).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13])
    15 -> (this as Function15<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, R>).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14])
    16 -> (this as Function16<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, R>).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15])
    17 -> (this as Function17<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, R>).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16])
    18 -> (this as Function18<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, R>).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17])
    19 -> (this as Function19<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, R>).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18])
    20 -> (this as Function20<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, R>).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19])
    21 -> (this as Function21<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, R>).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20])
    22 -> (this as Function22<Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, Any?, R>).invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], args[20], args[21])
    else -> (this as FunctionN<R>).invoke(*args)
}

Originally, I found these specifications regarding invoking functions and it looked super promising, but it seems those docs are outdated and no longer represent the current state. I tried looking for the equivalent in the current docs, but to no avail.

Additionally, I was also considering checking arity against the length of the arguments, but arity is contained in the FunctionBase interface and since that is in kotlin.jvm.internal, it seemed inappropriate to use.

I would appreciate any confirmation on my approach or suggestions on how to proceed otherwise. Thanks!

There is a function in the stdlib that does exactly this:
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-callable/call.html

Thanks for the quick reply! I am aware of that method, because I’m using it for member functions on a class. I wasn’t sure how to get a KCallable reference from a Lambda type.

Trying to use reflection on the Lambda types result in the following error:

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: class com.example$testExample$1$function$1

EDIT:

Just found this:

value.reflect().call("arg1", "arg2", ...)

But there is still an error:

Introspecting local functions, lambdas, anonymous functions and local variables is not yet fully supported in Kotlin reflection

EDIT 2:

Which makes sense given the docs I just found on it.

You can also use JVM reflection to call methods.

Gotcha. Just for clarities sake, this seems to work fine:

lambdaFunction::class.java.methods.find { it.name == "invoke" }.invoke(value, "arg1", "arg2", ...)

Though, I would love to just handle this as a KCallable, but it seems that I’ll have to wait for that. I appreciate the help and direction here. Thanks!