Explain the difference between a bound and an unbound callable reference, including how their function types differ.
answer
- Unbound = Class::m, receiver is a parameter
- Bound = obj::m, receiver baked in
- Bound drops the receiver from the type
- Bound receiver evaluated once at creation
- KProperty1 (unbound) vs KProperty0 (bound)
basics
~10 sUnbound references name a member on a class (Class::m) and take the receiver as a parameter. Bound references fix a specific object (obj::m), so the receiver is baked in and not a parameter.
solid answer
~40 sAn unbound reference like String::length is written against the class, so the receiver is still 'open': its type is (String) -> Int — you supply the instance when calling. A bound reference like "abc"::length captures a concrete receiver instance at creation time, so the receiver disappears from the signature: its type is () -> Int. Bound references can also capture this implicitly (this::method) or any expression (config::reload). Practically, unbound is ideal for collection ops where each element is the receiver (names.map(String::uppercase)), while bound is ideal for callbacks tied to one object (button.onClick(viewModel::submit)). Both produce KFunction/KProperty; a bound reference additionally exposes the captured receiver via boundReceiver-style internals, and KProperty getters/setters drop the receiver parameter accordingly.
code
kotlin · 8 linesclass User(var name: String)
fun greeter(u: User) = "Hi " + u.name
val u = User("Ada")
val unbound: (User) -> String = ::greeter // takes the User
val boundProp: () -> String = u::name // KProperty0 getter, no receiver
u.name = "Grace"
println(boundProp()) // "Grace" — reads live field, but on THIS ugo deeper
Can recognize Class::m vs obj::m and that one needs an instance and the other doesn't.
States both function types correctly and knows the receiver-as-parameter rule for unbound references.
Knows the receiver-evaluated-once semantics, the KProperty0/KProperty1 distinction, and picks bound vs unbound deliberately in APIs.
Reasons about lifetime/capture implications (e.g., a bound reference pinning an object alive) and consistency with how lambdas capture.
## The core distinction The difference is **whether the receiver is already supplied**. - **Unbound reference** — written against a *type*: `String::length`. No instance is captured. The receiver is the **first parameter** of the resulting function type. - **Bound reference** — written against an *instance expression*: `"hello"::length`. The instance is captured **at the moment you create the reference**. The receiver is **gone** from the signature. ## How the types change ```kotlin val unbound: (String) -> Int = String::length // receiver = parameter val bound: () -> Int = "hello"::length // receiver baked in -> no param class Counter(var n: Int) { fun inc() { n++ } } val c = Counter(0) val boundFn: () -> Unit = c::inc // operates on THIS c forever ``` Every extra explicit parameter the member declares stays in the type; only the **receiver** slot is what bound/unbound toggles. ## Implicit-receiver bound references Inside a class you can bind to the current instance: ```kotlin class Service { fun handle(e: Event) { /* ... */ } fun register(bus: EventBus) = bus.subscribe(this::handle) // bound to this } ``` `this::handle` is bound; `Service::handle` would be unbound with type `(Service, Event) -> Unit`. ## When evaluation happens (a real gotcha) For a bound reference, the **receiver expression is evaluated once, when the reference is created** — not on each call. `getCurrentUser()::name` snapshots the user returned right now; later changes to whatever `getCurrentUser()` would return are not reflected. ## Property references follow the same rule ```kotlin val p1: (String) -> Int = String::length // KProperty1, getter takes receiver val p2: () -> Int = "abc"::length // KProperty0, getter takes none ``` Unbound property refs are `KProperty1<T, V>` (one receiver); bound are `KProperty0<V>` (zero). ## Choosing between them - Use **unbound** when the data flow supplies the receiver per call (`list.map(String::uppercase)`). - Use **bound** for callbacks/handlers tied to one object (`viewModel::submit`, `this::onTick`).
- When is the receiver of a bound reference evaluated?Once, when the reference expression is created — not on each invocation. So obj::m snapshots which object, though it still reads the object's live state on each call.
- What KProperty subtype does an unbound property reference produce?KProperty1<T, V> (one receiver parameter); a bound one produces KProperty0<V>.
Unbound is a generic key-cutting machine that needs the blank you hand it; bound is a key already cut for one specific lock.
saying these in an interview costs you the question
- Claiming a bound reference re-evaluates its receiver expression on every call
- Saying bound and unbound have the same function type
- Forgetting the receiver becomes a parameter only in the unbound case
- Thinking this::method is unbound