Skip to content

Chapter 4 of 7

Functions, Lambdas, and Scope Functions

Functions are first-class citizens in Kotlin. A higher-order function is one that takes a function as a parameter or returns one, opening up powerful composition patterns. The function-typed parameters are typically supplied as lambdas — anonymous functions written as literals. With a single parameter, you can use the implicit name it; for several or explicit names, declare them in the parameter list, as in { x, y -> x + y }. Several modifiers refine higher-order functions. The inline keyword tells the compiler to copy the function body and its lambdas to the call site, avoiding the allocation of function objects and enabling the reified modifier for runtime type access. noinline opts a specific lambda out of inlining when it needs to be stored or passed further, and crossinline prevents non-local returns when the lambda will be invoked from a different execution context.

Reified type parameters unlock uses that generics normally forbid — most notably is T and T::class.java at runtime. Because type information is erased by the JVM, this trick works only inside inline functions where the type is preserved at the call site. The infix modifier lets a function be called without a dot or parentheses, as in 3 times "Hi ", giving DSL-like fluency to member or extension functions with a single argument (and no varargs or default values). Operator overloading works similarly: by marking a function with the operator keyword and using predefined names like plus, minus, times, divide, compareTo, get, set, contains, and invoke, you can use +, *, <, [], in, and other natural syntax. The invoke operator is particularly interesting — it lets an instance be called like a function, as in val g = Greeter(); g("Alice"), making objects suitable as callbacks and DSL builders.

Top-level functions are declared outside any class, package, or file scope. They default to public and compile to static methods on a synthetic class named after the file, providing a convenient way to expose utility functions without polluting the global namespace. Kotlin's class builder idiom relies on returning this from each setter-like method, ideally using apply so the chain composes naturally: Query().limit(5).select("*"). Labeled returns let you break out of a lambda early without exiting the enclosing function — return@forEach terminates the current iteration, and a custom label handles nested or shadowed cases.

The scope functions are a small family of standard-library helpers that wrap a block of code on an object, each with subtly different behavior. let references the receiver as it and returns the lambda result, ideal for null checks with ?.let { ... } and transformations. run references the receiver as this and returns the lambda result, useful for object configuration followed by computing a value. with takes the object as an argument (not as a receiver), so it works as a non-extension function — perfect for calling multiple methods on an object. apply references the receiver as this but returns the object itself, making it the idiomatic choice for initialization and builder chains. also references the receiver as it while returning the object, designed for side effects like logging or validation that keep the original flowing through a chain. Two related utilities complement the scope family: takeIf returns the object when its predicate is true and null otherwise; takeUnless does the opposite. The two main questions when choosing between them are whether you need the object back (apply, also) or a computed result (let, run, with), and whether you prefer referencing it as it or as this.

All chapters
  1. 1Foundations — Types, Variables, and Expressions
  2. 2Null Safety
  3. 3Classes, Objects, and Inheritance
  4. 4Functions, Lambdas, and Scope Functions
  5. 5Properties and Delegation
  6. 6Collections, Sequences, and Strings
  7. 7Coroutines and Flow

Drill it

Reading is not remembering. These come from the Kotlin Programming deck:

Q

What is null safety in Kotlin?

Null safety is a Kotlin feature that eliminates NullPointerException at compile time.By default, variables cannot hold null. You must explicitly declare a type...

Q

How do you declare a nullable type in Kotlin?

Append a ? to the type declaration:var name: String? = nullWithout the ?, the compiler will reject any attempt to assign null.

Q

What is the safe call operator in Kotlin?

The safe call operator ?. allows you to access a property or call a method on a nullable object without risking a NullPointerException:val length = name?.length...

Q

What is the Elvis operator in Kotlin?

The Elvis operator ?: provides a default value when an expression is null:val len = name?.length ?: 0If the left side is null, the right side is used.