What is a local (nested) function in Kotlin, and what is the main reason to use one instead of a private top-level or member function?
answer
- fun inside fun
- scoped to enclosing function only
- closes over outer locals/params
- good for one-off helpers + recursion
- captured var wrapped in Ref
basics
~20 sA local function is a function declared inside another function. The main reason to use one is to reuse a small piece of logic that only matters to the surrounding function, while reading its local variables directly.
solid answer
~40 sA local function is a `fun` declared inside the body of another function. It is only visible within its enclosing function's scope, so it keeps a helper private to where it's used. Crucially, it closes over the enclosing function's local variables and parameters, so you can read (and with `var`, mutate) them directly instead of threading them through parameters. That removes duplication without polluting the class with a `private` member that no other method needs. Typical uses: factoring out a repeated validation/transformation step inside one algorithm, or naming a recursive helper. Prefer it over a private member when the helper is meaningless outside the enclosing function and benefits from sharing its state.
code
kotlin · 6 linesfun greetAll(names: List<String>, greeting: String) {
fun greet(name: String) = println("$greeting, $name!") // captures greeting
names.forEach { greet(it) }
}
fun main() = greetAll(listOf("Ada", "Linus"), "Hello")go deeper
Knows the syntax (fun inside fun) and that it's only visible inside the enclosing function.
Explains closure over locals/params and picks local function vs private member appropriately.
Discusses return semantics, recursion, and the compiler's Ref wrapping for captured vars.
Weighs readability/encapsulation trade-offs and when extracting to a private/top-level function is the better design at scale.
## What it is A **local function** (also called a **nested function**) is a function defined inside the body of another function using the normal `fun` keyword. Its **scope** — the region where its name is visible — is limited to the enclosing function. Code outside cannot call it. ```kotlin fun printArea(width: Int, height: Int) { // local function, only visible inside printArea fun label(prefix: String, value: Int) { // closes over nothing extra here, just a helper println("$prefix = $value") } label("width", width) label("height", height) label("area", width * height) } ``` ## Closure: the key benefit A local function forms a **closure** — it captures ("closes over") the variables and parameters of its enclosing scope and can use them directly: ```kotlin fun validateUser(name: String, age: Int) { fun fail(field: String): Nothing = throw IllegalArgumentException("$field invalid for user $name") if (name.isBlank()) fail("name") // reads enclosing `name` if (age < 0) fail("age") } ``` The local function `fail` reads `name` from the outer scope without it being passed in. This avoids repeating the user context in every call. ## When to use it vs alternatives - **vs a `private` member function:** use a local function when the helper is meaningless outside the one function and benefits from sharing its locals. A `private` member is right when several methods reuse it. - **vs a `private` top-level function:** same idea — top-level is for reuse across the file; local is for one-function-only logic. - **vs a lambda:** a local function can be recursive (it has a name) and reads more clearly for multi-line logic; a lambda is better when you need to pass behavior as a value. ## Mechanics to know - Declared with `fun`, can have parameters, a return type, generics, and even nested local functions. - Can capture both `val` (read) and `var` (read and mutate) from the enclosing scope. - A bare `return` inside a local function returns from the **local function**, not the enclosing one (unlike an inline lambda). - Under the hood the compiler typically generates a synthetic class/method; captured `var`s are wrapped in a `Ref` holder so changes are visible to both scopes. ## Common idioms - **Factor recursion:** name a recursive helper inside a public function so the recursion isn't exposed. - **Share state:** accumulate into an enclosing `var`/collection without passing it around.
- Can a local function be called before it is declared in the enclosing function?No. Like local variables, a local function must be declared before the line that calls it; it isn't hoisted.
- Does a bare `return` inside a local function return from the outer function?No — it returns from the local function itself. Only inline lambdas allow a non-local `return` to the enclosing function.
Like a sticky note you write for yourself inside one task — useful right there, but you don't pin it to the whole office wall.
saying these in an interview costs you the question
- Claiming a local function is visible/callable from outside its enclosing function
- Saying local functions cannot access the outer function's variables
- Confusing a local function with a lambda and thinking `return` exits the outer function
- Asserting they hurt performance significantly in normal code
- Saying you must pass all outer state as parameters