Skip to content
Educora
Intermediate20 min5 / 14

Functions and lambdas

Write your own functions: default values and named arguments, single-expression functions, extension functions, lambdas and higher-order functions.

Check yourself
In this lesson you will learn
  • Define a function with parameters and a return type
  • Use default values, named arguments and single-expression functions
  • Add extension functions to existing types
  • Write a lambda and pass it to a higher-order function

Imagine you build the same greeting text in ten places in your program. When the text has to change, you will need to fix ten places! A function lets you write the code once, give it a name and call it as often as you like. You have already worked with functions: main, println and repeat are functions. Now you will create your own.

Declaring a function

A function starts with the word fun, followed by its name and its parameters in parentheses. In Kotlin every parameter must have a type: name: String. After the parentheses, a colon introduces the return type, and the result is given back with return. A function that returns nothing has the type Unit, and you can leave it out.

Kotlin
fun greet(name: String, greeting: String = "Hello"): String {
    return "$greeting, $name!"
}

fun printLine(length: Int = 10) {
    println("-".repeat(length))
}

fun main() {
    println(greet("Aysel"))
    println(greet("Murad", "Salam"))
    println(greet(greeting = "Hi", name = "Leyla"))
    printLine()
    printLine(5)
}
Expected output
Hello, Aysel!
Salam, Murad!
Hi, Leyla!
----------
-----
  • greeting: String = "Hello" is a default value: if no argument is given in the call, "Hello" is used.
  • greet(greeting = "Hi", name = "Leyla") uses named arguments: when you write the parameter names, the order does not matter and the code reads more clearly.
  • printLine returns nothing — its type is Unit; it just prints to the screen.

Single-expression functions

If the whole job of a function is to calculate one expression, you can drop the curly braces and return and write the expression after an = sign. The compiler infers the return type by itself. Since if and when are expressions, they can be used in such a function too.

Kotlin
fun square(x: Int) = x * x
fun isEven(n: Int) = n % 2 == 0
fun rectangleArea(width: Double, height: Double) = width * height
fun result(score: Int) = if (score >= 50) "passed" else "failed"

fun main() {
    println(square(7))
    println(isEven(10))
    println(rectangleArea(4.0, 2.5))
    println(result(73))
}
Expected output
49
true
10.0
passed

Extension functions

In Kotlin you can “add” a new function to an existing type, even to a standard type such as String or Int. To do this, write the type and a dot before the function name: fun String.shout(). Inside the function, this is the value itself. Such a function is then called like an ordinary method: "salam".shout().

Kotlin
fun String.shout() = uppercase() + "!"
fun Int.isEven() = this % 2 == 0
fun Double.toManat() = "$this AZN"

fun main() {
    println("salam".shout())
    println(8.isEven())
    println(12.5.toManat())
}
Expected output
SALAM!
true
12.5 AZN

Lambdas

A lambda is a short function without a name, written in curly braces: { x: Int -> x * 2 }. The parameters are to the left of the arrow and the body is to the right; the value of the last expression is the lambda's result. You can store a lambda in a variable, and its type is written like this: (Int) -> Int — “takes an Int, returns an Int”. If a lambda has only one parameter, you can leave it out and use the name it in the body.

Kotlin
fun main() {
    val double = { x: Int -> x * 2 }
    val add: (Int, Int) -> Int = { a, b -> a + b }
    val greet: (String) -> String = { "Hello, $it!" }
    println(double(21))
    println(add(3, 4))
    println(greet("Elvin"))
}
Expected output
42
7
Hello, Elvin!

Higher-order functions

A function that takes another function as a parameter (or returns one) is called a higher-order function. Below, applyTwice applies the operation it receives twice. If a lambda is the last argument, it can be written outside the parentheses. An existing function can be passed with ::, as in ::multiply.

Kotlin
fun applyTwice(x: Int, f: (Int) -> Int): Int = f(f(x))

fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
    return operation(a, b)
}

fun multiply(a: Int, b: Int) = a * b

fun main() {
    println(applyTwice(3) { it + 10 })
    println(applyTwice(5) { it * it })
    println(calculate(8, 2) { a, b -> a - b })
    println(calculate(8, 2, ::multiply))
}
Expected output
23
625
6
16
applyTwice(5) { it * it }: first 5 · 5 = 25, then 25 · 25 = 625.

The standard library is full of functions that take lambdas. Even repeat(3) { ... } from the previous lesson is a higher-order function! On strings, count counts the characters that match a condition, and filter keeps only those characters:

Kotlin
fun main() {
    val word = "Programming"
    println(word.count { it == 'm' })
    println(word.filter { it !in "aeiou" })
    println(word.any { it.isDigit() })
    repeat(2) { i -> println("Attempt ${i + 1}") }
}
Expected output
2
Prgrmmng
false
Attempt 1
Attempt 2
repeat passes the step number, starting from 0, to the lambda.

Key points

  • A function is written as fun name(param: Type): ReturnType { ... }; a function that returns nothing has the type Unit.
  • Default values make arguments optional, and named arguments remove the dependence on order.
  • Single-expression function: fun square(x: Int) = x * x.
  • An extension function adds a new method to an existing type: fun String.shout().
  • A lambda is an unnamed function: { a, b -> a + b }; a single parameter is called it.
  • A higher-order function takes another function as a parameter; a trailing lambda can go outside the parentheses.

Check yourself

10 questions. Every correct answer earns XP.

1 / 10
Given fun area(w: Int, h: Int = 2) = w * h, what is area(5)?