skip to content

Calling Members Reflectively

call invokes positionally while callBy takes a parameter map and honors default arguments, and isAccessible unlocks private members. The callBy detail matters because default arguments are invisible to plain Java reflection.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

How do you invoke a function at runtime using Kotlin reflection's KFunction.call(), and what arguments must you pass?

level: juniorimportance: must knowfreq 55%

answer

  1. call(vararg args) — positional, declaration order
  2. Member fn: receiver instance is the FIRST arg
  3. call() ignores defaults — use callBy() for those
  4. Needs kotlin-reflect on classpath
  5. Wrong count/type -> IllegalArgumentException

basics

~20 s

You 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 s

A 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 lines
kotlin
import 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

for a junior

Knows you call ::fn.call(args) positionally and that a member function needs the receiver first.

for a middle

Distinguishes call() vs callBy(), knows defaults aren't applied, and handles vararg/exception cases.

for a senior

Explains parameter kinds (INSTANCE/EXTENSION_RECEIVER/VALUE), kotlin-reflect requirement, and error semantics precisely.

for a principal

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)

context

open as a page

When should you use KFunction.callBy() instead of call(), and how do you build its KParameter map to honor default arguments?

level: middleimportance: must knowfreq 45%

basics

~20 s

Use callBy() when the function has default parameters and you only want to supply some of them. You pass a Map<KParameter, Any?> with entries only for the parameters you provide; omitted ones with defaults are filled in automatically.

open as a page

How do you read and write a property's value reflectively using KProperty.get() and the setter, including for member properties?

level: middleimportance: should knowfreq 40%

basics

~20 s

Get a KProperty for the field. To read, call get() (passing the receiver object for member properties). To write, the property must be a var (KMutableProperty); call its setter via .setter.call(receiver, newValue) or .set(receiver, newValue).

open as a page

What does setting isAccessible = true do on a KCallable, and what are the risks of reaching private members reflectively?

level: seniorimportance: should knowfreq 35%

basics

~20 s

isAccessible = true turns off the JVM access check so you can call() or get()/set() a private function, property, or constructor that you'd otherwise be blocked from. It's powerful but bypasses encapsulation and can break under the module system or a SecurityManager.

open as a page

When invoking reflectively, how do KParameter objects work — their kind, index, isOptional, isVararg — and how do you use them to build correct call/callBy invocations?

level: seniorimportance: nice to knowfreq 25%

basics

~20 s

Each parameter of a callable is a KParameter with a kind (instance receiver, extension receiver, or value), an index, a name, a type, and flags like isOptional and isVararg. You use these to know the right order for call() or to build the map for callBy().

open as a page