What is the `KFunction` type that a `::` reference produces, and what additional capabilities does it give you beyond plain invocation?
answer
- KFunction = callable + reflection metadata
- name / parameters / returnType / visibility
- Flags: isSuspend, isInline, isOperator, isInfix
- callBy respects default arguments
- Rich reflection needs kotlin-reflect on classpath
basics
~10 sA :: reference is a KFunction object. Besides being callable, it carries reflection info — you can read its name, parameters, return type, and modifiers like whether it's suspend or inline.
solid answer
~30 s`::` produces a value implementing **`KFunction<R>`** (from `kotlin.reflect`), which also implements the matching `FunctionN`/`(P...) -> R` type so you can invoke it directly. Beyond invocation it exposes reflective metadata: `.name`, `.parameters` (a `List<KParameter>`), `.returnType` (a `KType`), `.visibility`, and flags `isInline`, `isOperator`, `isInfix`, `isSuspend`, `isExternal`. You can also `call(...)` / `callBy(map)` to invoke reflectively (the latter respecting default arguments), and there are specialized subtypes `KFunction0..KFunctionN`. Using these requires the `kotlin-reflect` library on the classpath. It's powerful for serialization/DI frameworks but slower than direct calls, so reserve reflection for framework-level code.
code
kotlin · 12 linesimport kotlin.reflect.full.callSuspend // example import
fun greet(name: String): String = "Hi $name"
fun main() {
val ref = ::greet
println(ref()) // direct invoke (it's a (String)->String)
println(ref.name) // greet
println(ref.parameters.size) // 1
println(ref.returnType) // kotlin.String
println(ref.isSuspend) // false
}go deeper
Knows the reference can be invoked; unaware of reflection metadata.
Knows KFunction exposes name/parameters and that it's also a normal function type.
Uses callBy/parameters/flags, understands the kotlin-reflect dependency and performance cost.
Designs framework-level introspection (DI/serialization), weighs reflection cost vs codegen, and isolates reflective paths from hot code.
## What `KFunction` is Every `::` reference is an instance of **`KFunction<out R>`** from the `kotlin.reflect` package. Crucially it *also* implements the ordinary function type (`KFunction1<A, R>` is a `(A) -> R`), so you can just call it. The 'K' types are Kotlin's **reflection** interfaces (`KFunction`, `KProperty`, `KClass`, `KParameter`, `KType`). ## Beyond invocation: metadata ```kotlin fun greet(name: String): String = "Hi $name" val ref = ::greet println(ref.name) // "greet" println(ref.returnType) // kotlin.String println(ref.parameters.map { it.name }) // [name] println(ref.isInline) // false println(ref.isSuspend) // false ``` Useful members of `KFunction`: - `name`: the declared name. - `parameters`: `List<KParameter>` (name, type, kind: VALUE/INSTANCE/EXTENSION_RECEIVER, `isOptional`). - `returnType`: a `KType`. - `visibility`: PUBLIC/INTERNAL/PROTECTED/PRIVATE. - flags: `isInline`, `isOperator`, `isInfix`, `isSuspend`, `isExternal`, `isAbstract`, `isFinal`, `isOpen`. ## Reflective invocation ```kotlin ref.call("Ada") // positional reflective call // callBy respects default args: fun f(a: Int, b: Int = 10) = a + b val kf = ::f val byName = kf.parameters.associateWith { p -> if (p.name == "a") 1 else null } // callBy lets you omit optional params that have defaults ``` `callBy(Map<KParameter, Any?>)` is what frameworks use to honor **default arguments** without enumerating every overload. ## The `kotlin-reflect` dependency Full reflection (reading parameters/types, `callBy`) requires the **`kotlin-reflect`** artifact on the classpath. Plain invocation and `.name` for simple cases work without it, but rich introspection throws/`KotlinReflectionNotSupportedError` without the library. ## Specialized subtypes `KFunction0<R>`, `KFunction1<P1, R>`, … give statically-typed `invoke`. The compiler assigns the right one based on arity. ## When to use - DI/serialization/validation frameworks introspecting constructors and functions. - Building dynamic dispatch or scripting layers. ## Cost Reflective `call`/`callBy` is markedly slower than direct invocation and defeats inlining. Use references as plain callables in hot paths and reserve reflection for setup/framework code.
- What does `callBy` give you that plain `call` doesn't?`callBy(Map<KParameter, Any?>)` lets you invoke while omitting optional parameters, so the function's default argument values are applied — essential for frameworks instantiating objects with partial inputs.
- Why might `.parameters` fail at runtime?Rich reflection needs the `kotlin-reflect` artifact on the classpath; without it, deep introspection throws `KotlinReflectionNotSupportedError`.
A KFunction is a labeled tool: you can use it (invoke) and also read the label — its name, what inputs it expects, and what it returns.
saying these in an interview costs you the question
- Thinking a reference is only callable and carries no metadata
- Believing full reflection works without `kotlin-reflect`
- Claiming reflective `call` is as fast as a direct call
- Not knowing `callBy` honors default arguments
- Confusing `KFunction` with `KProperty` or `KClass`