Explain the KCallable hierarchy — KCallable, KFunction, KProperty — and how you call or read members reflectively.
answer
- KCallable = root: call() and callBy()
- KFunction = functions/constructors; KProperty = read
- KProperty0/1/2 by receiver count; KMutable adds set
- callBy honors default parameter values
- isAccessible=true to reach private members
basics
~10 sKCallable is the common type for anything you can call: functions and properties. KFunction is invoked with call(args). KProperty has a getter you read with get(receiver); mutable ones (KMutableProperty) also have a setter.
solid answer
~30 sKCallable<R> is the supertype of all callable members; it carries name, parameters (List<KParameter>), returnType, visibility, and annotations, and offers call(vararg args) and callBy(Map<KParameter, Any?>). KFunction<R> represents functions and constructors — invoked via call() or callBy(), the latter respecting default parameter values. KProperty<R> represents read access through a nested getter (KProperty.Getter, itself a KFunction); KProperty0/1/2 differ by receiver count (no receiver, one, two for extensions). KMutableProperty adds a setter. You read with property.get(receiver) and write with mutableProp.set(receiver, value). Property and function references (::foo, String::length) produce these objects. callBy is what enables data-class deserialization libraries to honor defaults and skip absent parameters.
code
kotlin · 11 linesimport kotlin.reflect.full.primaryConstructor
data class User(val id: Long, val name: String = "anon")
fun main() {
val ctor = User::class.primaryConstructor!!
val idParam = ctor.parameters.first { it.name == "id" }
// name omitted -> default "anon" used
val u = ctor.callBy(mapOf(idParam to 7L))
println(u) // User(id=7, name=anon)
}go deeper
Knows functions and properties can be called/read via references like ::foo.
Explains the KCallable/KFunction/KProperty split and call vs callBy with defaults.
Maps the arity variants and getter/setter structure and ties callBy to serialization defaults.
Weighs reflective callBy cost vs generated code, and considers accessibility/security implications of opening private members.
## The KCallable hierarchy `KCallable<R>` is the root interface for **anything callable** in Kotlin reflection, where `R` is the return/value type. Its key members: - `name: String` - `parameters: List<KParameter>` — including receivers and the instance parameter - `returnType: KType` - `visibility`, `isAbstract`, `isFinal`, `isSuspend` - `annotations: List<Annotation>` - `call(vararg args: Any?): R` — positional invocation - `callBy(args: Map<KParameter, Any?>): R` — named invocation honoring **default values** ### KFunction `KFunction<R>` represents functions, methods, and constructors. You get one from a **function reference** (`::myFun`, `String::length` as a method) or from `kClass.functions`/`primaryConstructor`. ```kotlin fun greet(name: String) = "Hi $name" val f: KFunction<String> = ::greet println(f.call("Ada")) // Hi Ada ``` ### KProperty and arity variants `KProperty<R>` represents a property; read access goes through its nested `getter: Getter` (which is itself a `KFunction`). The arity subtypes encode receivers: - `KProperty0<R>` — no receiver (top-level/local): `get()` - `KProperty1<T, R>` — one receiver (member): `get(receiver)` - `KProperty2<D, E, R>` — two receivers (member extension) `KMutableProperty1<T, R>` adds `set(receiver, value)`. ```kotlin data class Box(var v: Int) val p = Box::v // KMutableProperty1<Box, Int> val b = Box(1) println(p.get(b)) // 1 p.set(b, 42) println(p.get(b)) // 42 ``` ## call vs callBy `call` requires **every** parameter positionally. `callBy` takes a `Map<KParameter, Any?>` and fills in **default parameter values** for any absent keys — essential for constructing data classes from partial data, which is exactly how serialization/deserialization frameworks honor defaults. ## isAccessible Private members must be opened first via `member.isAccessible = true` (from `kotlin.reflect.jvm`) before `call`/`get` succeeds.
- Why do deserialization libraries prefer callBy over call?callBy accepts a partial map of KParameters and supplies default values for missing optional parameters, so absent JSON fields fall back to declared defaults.
- What's the difference between KProperty1 and KProperty0?KProperty0 has no receiver (its get() takes no argument), while KProperty1's get(receiver) needs the instance whose property you read.
saying these in an interview costs you the question
- Saying call and callBy are interchangeable
- Not knowing callBy respects default values
- Confusing the receiver arity of KProperty0/1/2
- Forgetting isAccessible for private members
- Thinking KProperty can write without KMutableProperty