skip to content

How Kotlin Does Functions

Kotlin treats functions as first-class and declarable anywhere, adds extensions so you can grow types you do not own, and uses named and default arguments to keep call sites readable. This orientation explains why Kotlin APIs look so different from Java ones.

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

questions

6

What does it mean that functions are 'first-class' in Kotlin, and how does that differ from how Java traditionally modeled functions?

level: juniorimportance: must knowfreq 70%

answer

  1. Value: store, pass, return
  2. Function type (Int) -> String is real
  3. Lambda / anonymous fun / :: reference
  4. Higher-order = takes/returns a function
  5. Java pre-8 needed SAM interface

basics

~20 s

First-class means a function is a value: you can store it in a variable, pass it to another function, and return it. In Kotlin you do this directly; old Java needed an interface or anonymous class wrapper.

solid answer

~40 s

In Kotlin a function is a value with a function type like `(Int) -> String`. You can assign it to a `val`, pass it as an argument, or return it. You produce these values with lambdas `{ x -> ... }`, anonymous functions `fun(x: Int) = ...`, or function references `::name` / `String::length`. Higher-order functions take or return such values. Java historically had no function values: you simulated them with single-method interfaces (later `@FunctionalInterface` + lambdas in Java 8). Kotlin bakes function types into the type system, so `(Int) -> String` is a real type, not just sugar over an interface. Under the hood the compiler still represents these as `FunctionN` interface instances on the JVM, but the language treats them as ordinary values.

code

kotlin · 6 lines
kotlin
fun applyTwice(x: Int, op: (Int) -> Int): Int = op(op(x))

val inc: (Int) -> Int = { it + 1 }
println(applyTwice(3, inc))        // 5
println(applyTwice(3, ::square))   // 81  (function reference)
fun square(n: Int) = n * n

go deeper

for a junior

Can state the store/pass/return definition and write a lambda assigned to a val.

for a middle

Distinguishes lambdas, anonymous functions, and references; uses higher-order functions like map.

for a senior

Explains the FunctionN JVM representation and contrasts with Java functional interfaces and SAM conversion.

for a principal

Discusses inlining to erase the FunctionN allocation, API design with function-type parameters, and interop tradeoffs.

## What 'first-class' means A value is **first-class** in a language if it can be: stored in a variable, passed as an argument, and returned from a function. In Kotlin, **functions are first-class values** — they sit alongside `Int`, `String`, etc. ## Function types Kotlin has dedicated **function types** written as `(ParamTypes) -> ReturnType`. Examples: - `() -> Unit` — takes nothing, returns `Unit` (Kotlin's `void`-like type). - `(Int, Int) -> Int` — takes two `Int`s, returns an `Int`. - `(String) -> Boolean` — a predicate. A variable can hold one: ```kotlin val add: (Int, Int) -> Int = { a, b -> a + b } val result = add(2, 3) // invoke like a normal function -> 5 ``` ## Ways to create a function value - **Lambda**: `{ a, b -> a + b }` — an anonymous function expression. - **Anonymous function**: `fun(a: Int, b: Int): Int = a + b` — like a lambda but allows explicit return type and `return`. - **Function reference** with `::` — `::println`, `String::length`, `instance::method`. ## Higher-order functions A **higher-order function** takes a function as a parameter and/or returns one. This is what makes `map`, `filter`, `forEach` possible: ```kotlin fun <T> List<T>.myFilter(keep: (T) -> Boolean): List<T> { /* ... */ } listOf(1, 2, 3).myFilter { it > 1 } // pass a predicate value ``` ## Contrast with traditional Java Before Java 8, Java had no function values. You emulated them with a **single-abstract-method interface** (e.g. `Runnable`, `Comparator`) and an anonymous class. Java 8 added lambdas, but they are still typed as **functional interfaces** — there is no standalone `(Int) -> String` type. Kotlin makes the function type a real, named-by-shape type in the type system. ## On the JVM Kotlin compiles a function value to an instance of a generated `FunctionN` interface (`Function0`, `Function1`, ... with an `invoke` method). So interop is smooth, but you write and reason about it as a plain value — that is the first-class part.

  • What concrete JVM type does a Kotlin lambda compile to?
    An instance of a generated FunctionN interface (Function0, Function1, ...) whose single `invoke` method holds the body.
  • Name three ways to obtain a function value in Kotlin.
    A lambda `{ ... }`, an anonymous function `fun(...) {...}`, and a function reference like `::foo` or `String::length`.

A function value is like a recipe card you can hand to someone, file away, or get back — not a meal you can only eat in place.

saying these in an interview costs you the question

  • Claiming Kotlin lambdas are 'just syntax' with no underlying type
  • Saying you cannot store a function in a variable
  • Confusing function type (Int)->String with a generic class
  • Thinking only methods inside classes can be passed around
  • Asserting Java always had first-class functions

context

open as a page

How do extension functions fit the Kotlin function model, and what does the receiver let you do that a plain top-level function does not? What are the key limits?

level: middleimportance: must knowfreq 65%

basics

~20 s

An extension function looks like a method added to an existing type. You write fun String.shout() = uppercase() + "!" and call "hi".shout(). It is really a static function with the receiver as a hidden first argument; it cannot access private members and is resolved statically.

open as a page

Explain named and default arguments in Kotlin. How do they reduce overloads, and what interop/ordering rules must you keep in mind?

level: middleimportance: must knowfreq 60%

basics

~20 s

A default argument gives a parameter a value used when the caller omits it. A named argument lets the caller pass values by parameter name instead of position. Together they remove the need for many overloaded versions of the same function.

open as a page

Where can a Kotlin function be declared (top-level, member, local), and what is the practical reason to choose a top-level function over a static helper class?

level: middleimportance: should knowfreq 55%

basics

~20 s

You can declare a function directly in a file (top-level), inside a class (member), or inside another function (local). Top-level functions need no wrapper class, so they replace Java's 'Utils' classes full of static methods.

open as a page

How do `operator` and `infix` functions extend the function model in Kotlin? Give the rules and a concrete example of each.

level: seniorimportance: should knowfreq 45%

basics

~20 s

operator lets a function back a symbol like +, [], or in, so a + b calls a.plus(b). infix lets you call a one-parameter function without the dot and parentheses, like 1 to 2. Both are syntax sugar over normal functions.

open as a page

In Kotlin's function model, what do `Unit` and `Nothing` mean as return types, and how does an expression-body function differ from a block-body one?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Unit is the return type for functions that do something but have no useful result (like Java's void). Nothing means the function never returns normally (it always throws or loops). An expression-body function uses = and infers its type; a block-body uses { } and return.

open as a page