How do you invoke a function at runtime using Kotlin reflection's KFunction.call(), and what arguments must you pass?
answer
- call(vararg args) — positional, declaration order
- Member fn: receiver instance is the FIRST arg
- call() ignores defaults — use callBy() for those
- Needs kotlin-reflect on classpath
- Wrong count/type -> IllegalArgumentException
basics
~20 sYou get a KFunction (for example from ::myFunc or a KClass member) and call its call(...) method, passing the arguments in the same order the function declares them. For a member function, the first argument is the receiver object.
solid answer
~30 sA KFunction obtained via a callable reference (::greet) or from KClass.memberFunctions/declaredFunctions exposes call(vararg args: Any?): R. You pass every parameter positionally, in declaration order. For an instance (member) function the receiver instance is the first argument, then the regular parameters; top-level and static functions take only their declared parameters. The number and types of args must match the function's parameters exactly or call() throws IllegalArgumentException (or IllegalCallableAccessException for inaccessible members). call() needs values for ALL parameters and ignores default values — for defaults use callBy(). Requires the kotlin-reflect dependency on the classpath; without it, member reflection throws KotlinReflectionNotSupportedError.
code
kotlin · 9 linesimport kotlin.reflect.full.memberFunctions
class Calc { fun mul(a: Int, b: Int) = a * b }
fun main() {
val fn = Calc::class.memberFunctions.first { it.name == "mul" }
val result = fn.call(Calc(), 6, 7) // receiver, then args
println(result) // 42
}go deeper
Knows you call ::fn.call(args) positionally and that a member function needs the receiver first.
Distinguishes call() vs callBy(), knows defaults aren't applied, and handles vararg/exception cases.
Explains parameter kinds (INSTANCE/EXTENSION_RECEIVER/VALUE), kotlin-reflect requirement, and error semantics precisely.
Weighs reflective invocation cost vs alternatives (codegen, lambdas, MethodHandles) and designs safe wrappers around call().
## What KFunction.call() does `KFunction<R>` is the reflection type for a callable function. Its key method is: ```kotlin fun call(vararg args: Any?): R ``` It invokes the underlying function dynamically and returns the result. You obtain a `KFunction` from a **callable reference** (`::topLevelFn`, `String::length`, `instance::method`) or from a `KClass` via `memberFunctions`, `declaredFunctions`, `functions`, or `constructors`. ## Passing arguments `call()` is **positional**: pass one value per `KParameter` in `parameters` order. - **Top-level / object function**: pass only the declared value parameters. - **Member (instance) function**: the FIRST argument is the **receiver instance** (the `INSTANCE` kind parameter), then the value parameters. - **Extension function**: receiver(s) come first as parameters too. ```kotlin fun add(a: Int, b: Int) = a + b val kf = ::add // KFunction2<Int, Int, Int> val r = kf.call(2, 3) // 5 class Greeter { fun hello(name: String) = "hi $name" } val m = Greeter::class.memberFunctions.first { it.name == "hello" } m.call(Greeter(), "Ann") // receiver first, then "Ann" ``` ## Rules and failure modes - You must supply **every** parameter; `call()` does NOT apply default values. Use `callBy()` for defaults. - Argument count/type mismatch → `IllegalArgumentException`. - Calling a `private`/inaccessible member without setting `isAccessible = true` → `IllegalCallableAccessException`. - `vararg` parameters are passed as a single array argument. - Requires the **kotlin-reflect** artifact; otherwise a `KotlinReflectionNotSupportedError` is raised for full member reflection. The return type is `R`, but through erasure you usually get `Any?` and cast.
- What happens if you pass two args to a function that needs three via call()?call() throws IllegalArgumentException — it requires a value for every parameter and does not fill in defaults.
- Why is the receiver passed as an argument for member functions?A member function has an instance (dispatch receiver) KParameter of kind INSTANCE; call() treats it as the first positional argument so it knows which object to invoke on.
call() is like dialing every digit of a phone number yourself — you must enter all of them in order; speed-dial defaults (callBy) come separately.
saying these in an interview costs you the question
- Claiming call() applies default parameter values
- Forgetting the receiver instance for a member function
- Saying kotlin-reflect isn't needed for member reflection
- Thinking arguments can be passed by name with call()
- Confusing call() (positional) with callBy() (by-parameter map)