skip to content

What does the :: operator do when applied to a function name, e.g. `::println` or `String::length`, and what is the resulting value?

level: juniorimportance: must knowfreq 70%

answer

  1. :: = reference, not call
  2. Result is KFunction (also a (P)->R)
  3. ::topLevel has no receiver
  4. Type::member leaves receiver as first param
  5. Pass where a lambda is expected

basics

~20 s

The :: operator turns a named function into a value you can store in a variable or pass to another function, instead of calling it. The result is a function object you can invoke later.

solid answer

~30 s

`::` creates a callable reference: it takes a declared `fun` and produces a first-class value implementing the `KFunction` interface (a subtype of the matching `FunctionN` type). `::println` references a top-level function; `String::length` references a member with the receiver still unbound (it becomes the first parameter). You can store the reference in a `val`, pass it where a lambda is expected (`list.map(String::length)`), and invoke it with `()`. It's the function-reference equivalent of a lambda but points at an existing declaration, so it avoids wrapping the call in `{ it.length }`.

code

kotlin · 8 lines
kotlin
fun square(x: Int) = x * x

fun main() {
    val f: (Int) -> Int = ::square   // reference, not invoked
    println(f(5))                    // 25 — invoked here
    println(listOf(1, 2, 3).map(::square))   // [1, 4, 9]
    println(listOf("a", "bb").map(String::length)) // [1, 2]
}

go deeper

for a junior

Knows :: makes a function into a passable value and can use list.map(::fn).

for a middle

Explains the KFunction result type and that Type::member leaves the receiver unbound as the first parameter.

for a senior

Discusses overload resolution of references and reflection metadata carried by KFunction.

for a principal

Frames references vs lambdas in terms of API ergonomics, reflection cost, and binary compatibility of exposed signatures.

## What `::` is The double-colon `::` is Kotlin's **callable reference** operator. Instead of *calling* a function, it produces a **value that represents the function** — a first-class object you can store, pass, and invoke later. ```kotlin fun greet(name: String) = "Hi $name" val ref = ::greet // a value, NOT a call val msg = ref("Ada") // invoke later -> "Hi Ada" ``` ## The type produced The reference is an instance of **`KFunction`** (from `kotlin.reflect`), which also implements the ordinary function type `(P...) -> R`. So `::greet` has type `KFunction1<String, String>` and is usable anywhere a `(String) -> String` is expected: ```kotlin val names = listOf("Ada", "Linus") val msgs = names.map(::greet) // ["Hi Ada", "Hi Linus"] ``` ## Top-level vs member references - `::println` — a **top-level** function reference; no receiver involved. - `String::length` — a **member/unbound** reference. The receiver (`String`) is *not* supplied, so it becomes the **first parameter**: the type is roughly `(String) -> Int`. ```kotlin listOf("a", "bb").map(String::length) // [1, 2]; each string is the receiver arg ``` ## Why use it instead of a lambda A reference points at an existing declaration, so `list.map(::greet)` is clearer and slightly cheaper than `list.map { greet(it) }`. It also carries reflection metadata (name, parameters) via the `KFunction` interface. ## Key terms - **Callable reference**: a value pointing at a declared function/property. - **`KFunction`**: the reflective type of that value; also a normal function type. - **Receiver**: the object a member function is called *on* (the `this`).

  • Can you pass `::println` directly to `forEach`?
    Yes: `list.forEach(::println)`. `println` overloads on the argument type and Kotlin resolves the one matching the element type, producing a `(T) -> Unit` reference.
  • What's the difference between `::greet` and `{ greet(it) }`?
    Both are usable as `(String)->String`. The reference points at the existing declaration and carries reflection metadata; the lambda is a fresh anonymous function wrapping the call.

A function reference is like saving someone's phone number (the reference) versus actually dialing it (the call) — you hold it now and dial later.

saying these in an interview costs you the question

  • Thinking `::greet` calls the function immediately
  • Saying the result is a String/return value rather than a function object
  • Not knowing `String::length` makes the receiver the first parameter
  • Confusing `::` with `.` member access
  • Believing references only work with lambdas, not vals

context