ZetCode

Kotlin functions

last modified July 5, 2020

Kotlin functions tutorial shows how to use functions in Kotlin language.

Functions in Kotlin are declared with the fun keyword. The body of a function is called a block and is enclosed within { } curly brackets. Functions may return values with the return keyword.

Functions in Kotlin are first-class citizens: they can be stored in variables and data structures, passed as arguments to and returned from other higher-order functions. We can use functions in any way that is possible for other non-function values.

Kotlin function definition

A function is a code block containing a series of statements. It is a good programming practice for functions to do only one specific task. Functions bring modularity to programs. Functions have the following advantages:

A function signature is a unique identification of a function for the Kotlin compiler. The signature consists of a function name, its parameters, and the return type.

Kotlin function naming

Any legal character can be used in the name of a function. By convention, function names begin with an lowercase letter. The function names are verbs or verbs followed by adjectives or nouns. Each subsequent word starts with an uppercase character. The following are typical names of functions in Kotlin:

Kotlin uses lowerCamelCase convention for function names. Other programming languages might use CamelCase or snake_case.

Kotlin main function

The main() function is the entry point to the Kotlin program.

main_fun.kt
package com.zetcode

fun main() {

    println("main function is an entry point")
}

The program prints a simple message to the terminal.

fun main() {

    println("main function is an entry point")
}

This is the entry point of the Kotlin program. The main() function does not take any parameters.

main_args.kt
package com.zetcode

fun main() {

    val sumVal = args.map { it.toInt() }.sum()
    println("The sum of values is $sumVal")
}

In this example, the program takes parameters; we assume string integers. We transform these strings into integers and compute their sum. Note that sum() and println() are also functions; they are Kotlin built-in functions.

Kotlin built-in functions

Kotlin standard library comes with many built-in functions.

builtins.kt
package com.zetcode

import kotlin.random.Random

fun main() {

    println("There is a majestic hawk in the sky")

    val r = Random.nextInt(0, 100)
    println(r)

    val word = "ocean"
    val letters = word.toCharArray()

    letters.forEach(::println)
}

The example presents four Kotlin built-in functions.

println("There is a majestic hawk in the sky")

The println() function outputs data on the terminal.

val r = Random.nextInt(0, 100)

The Random.nextInt() function returns a random value from the specified range.

val letters = word.toCharArray()

The toCharArray() function returns all chars from the string in an array.

letters.forEach(::println)

The forEach() function iterates over the values of the array.

There is a majestic hawk in the sky
29
o
c
e
a
n

This is the output.

Kotlin function return values

Functions may return values. To return values, we use the return keyword.

returning.kt
package com.zetcode

fun square(x: Int): Int {

    return x * x
}

fun square2(x: Int): Int = x * x


fun main() {

    println(square(5))
    println(square2(6))
}

In the example, we have two square functions.

fun square(x: Int): Int {

    return x * x
}

When a funcion has a body enclosed by curly brackets, it returns a value using the return keyword.

fun square2(x: Int): Int = x * x

The return keyword is not used for functions with expression bodies.

Kotlin function parameters

Functions in Kotlin may take parameters. The parameters are specified between () brackets and are separated by comma. Function parameters are defined using Pascal notation, i.e. name: type. Each parameter must be explicitly typed.

params.kt
package com.zetcode

fun sum(a: Int, b: Int): Int {
    return a + b
}

fun main() {

    val r = sum(4, 3)
    println(r)
}

In the example, we have a custom sum() function.

fun sum(a: Int, b: Int): Int {
    return a + b
}

The sum() function returns the sum of its two parameters. The parameters and the return values are integers.

val r = sum(4, 3)

The sum() function is called and the return value is assigned to the r variable.

Kotlin function default argument values

Kotlin function arguments may have default values; they are used if no value is provided for the argument.

default_values.kt
package com.zetcode

fun power(a: Int, b: Int = 2): Int {

    if (b == 2) {

        return a * a
    }

    var value = 1

    repeat(b) {
        value *= a
    }

    return value;
}

fun main() {

    val r1 = power(3)
    println(r1)

    val r2 = power(3, 3)
    println(r2)
}

We have created a power function. The function has one argument with an implicit value. We can call the function with one or two arguments.

9
27

This is the output.

Kotlin void return type

Kotlin functions must specify their return types; the exception is when they do not return any value. The return type for a void is Unit; this type may be omitted.

void_ret.kt
package com.zetcode

fun showGreeting(name: String): Unit {

    println("Hello $name")
}

fun main() {

    showGreeting("Arnold")
    showGreeting("Lucia")
}

The example shows greetings.

fun showGreeting(name: String): Unit {

    println("Hello $name")
}

The showGreeting() function prints a message to the terminal; it does not return anything. Therefore, the return type is specified as Unit.

Hello Arnold
Hello Lucia

This is the output.

Kotlin single-expression functions

When the body of a function contains a single expression, the curly braces can be omitted and the body is specified after the = symbol.

single_expr.kt
package com.zetcode

fun double(num: Int): Int = num * 2
fun triple(num: Int) = num * 3

fun main() {

    val r1 = double(3)
    val r2 = triple(3)

    println(r1)
    println(r2)
}

The example contains two single-expression functions.

fun double(num: Int): Int = num * 2

The function returns the parameter multiplied by 2. The curly brackets and the return keyword are omitted.

fun triple(num: Int) = num * 3

The return type can be omitted; it is inferred by Kotlin.

Kotlin variable number of arguments

A function can take variable number of arguments. For this we use the vararg keyword.

var_args.kt
package com.zetcode

fun mysum(vararg vals: Int): Int {

    return vals.sum()
}

fun main() {

    val s1 = mysum(1, 2, 3)
    val s2 = mysum(1, 2, 3, 4)
    val s3 = mysum(1, 2, 3, 4, 5)

    println(s1)
    println(s2)
    println(s3)
}

We create a mysum() function which can take variable number of arguments. The function calculates the sum of values passed to the function.

fun mysum(vararg vals: Int): Int {

    return vals.sum()
}

By using the vararg keyword, the mysum() function can take variable number of parameters. The vals variable is a Kotlin array.

val s1 = mysum(1, 2, 3)
val s2 = mysum(1, 2, 3, 4)
val s3 = mysum(1, 2, 3, 4, 5)

We call the mysum() function three times. Each time the number of parameters is different.

6
10
15

This is the output of the example.

Kotlin function recursion

Recursion, in mathematics and computer science, is a way of defining functions in which the function being defined is applied within its own definition. In other words, a recursive function calls itself to do its job. Recursion is a widely used approach to solve many programming tasks.

A typical example is the calculation of a factorial.

recursion.kt
package com.zetcode

fun fact(num: Int): Int {

    return if (num == 1) {
        num
    } else {
        num * fact(num - 1)
    }
}

fun main() {

    val f1 = fact(5)
    val f2 = fact(8)
    val f3 = fact(12)

    println(f1)
    println(f2)
    println(f3)
}

In this code example, we calculate the factorial of three numbers.

num * fact(num - 1)

Inside the body of the fact() function, we invoke the fact() function with a modified argument. The function calls itself.

120
40320
479001600    

These are the results.

Kotlin anonymous functions

Anonymous functions are functions that do not have a name. Anonymous functions reduce the coding overhead by eliminating the need to create a separate funcion.

anonym.kt
package com.zetcode

fun main() {

    val vals = intArrayOf(-2, -1, 0, 1, 2, 3, 4)

    val filtered = vals.filter(fun(el) = el > 0)
    println(filtered)
}

We have an array of integers. The array is filtered with the filter() function. It takes an anonymous function as a parameter.

val filtered = vals.filter(fun(el) = el > 0)

The anonymous function is used to filter the array.

[1, 2, 3, 4]

We have filtered out negative values.

Kotlin closures

Closures are functions that can access and modify properties defined outside the scope of the function.

closures.kt
package com.zetcode

fun makeAverager(): (n: Int) -> Double {

    val nums = arrayListOf<Int>()

    return fun(num: Int): Double {

        nums.add(num)
        val total = nums.sum()

        return total.toDouble() / nums.size
    }
}


fun main() {

    val avg = makeAverager()

    println(avg(1))
    println(avg(2))
    println(avg(3))
    println(avg(4))
    println(avg(5))
}

The example creates a function that calculates the average of the added values. It uses an anonymous function, which calculates the average from the list of values. The anonymous function has access to the nums list, which stores the values and is defined outside of the function body of the anonymous function.

1.0
1.5
2.0
2.5
3.0

This is the output.

Kotlin local functions

Local functions are defined inside other functions.

local_fun.kt
package com.zetcode

fun main() {

    fun buildMessage(name: String?): String {

        return "Hello $name"
    }

    print("Enter your name: ")
    val name = readLine()

    val message = buildMessage(name)
    println(message)
}

In the example, we have a local function buildMessage(), which is defined and called inside the main() function.

Kotlin extension functions

An extension function is function that can be added to an existing type without needing to derive a class from it. Extension functions are called like normal member functions. Extension functions allow us to add functionality to classes that were not created by us and when inheritance is not possible or makes no sense.

extension_fun.kt
package com.zetcode

fun String.second(): Char = this[1]

fun main() {

    val word = "falcon"
    println(word.second())
}

The example adds a new function to the String type. The function returns the second char of the string.

Kotlin member functions

Member functions are functions defined within a Kotlin class.

member_fun.kt
package com.zetcode

class Cat {

    fun talk() {
        println("meow")
    }
}

fun main() {

    val missy = Cat()
    missy.talk()
}

The talk() function is defined in the Cat class.

val missy = Cat()
missy.talk()

We create the Cat object and call the member function using the dot operator.

Kotlin high-order functions

A higher-order function is a function that takes functions as parameters, or returns a function.

highorder_fun.kt
package com.zetcode

fun process(data: IntArray, f: (IntArray) -> Any): Any {

    return f(data)
}

fun main() {

    val values = intArrayOf(1, 2, 3, 4, 5, 6)

    val res1 = process(values, IntArray::sum)
    println(res1)

    val res2 = process(values, IntArray::average)
    println(res2)
}

In the example, we have the process() high-order function, which takes two parameters: an integer array and a function. The function is applied on the elements of the array.

fun process(data: IntArray, f: (IntArray) -> Any): Any {

    return f(data)
}

The process() high-order function applies the function on the data array.

val res1 = process(values, IntArray::sum)
println(res1)

We pass the IntArray's sum() function to the process() function.

Kotlin infix functions

Functions can be called using so called infix notation. Infix notation is a syntactic sugar for visually improving the code. The notation omits the dot and the parentheses. There are several built-in functions that can be called with infix notation, e.g. to(), and(), or matches().

Infix functions are created with the infix keyword. They must be member functions or extension functions, they must have a single parameter, and the parameter must not accept variable number of arguments and must have no default value.

infix_builtin.kt
package com.zetcode

fun main() {

    val a = true
    val b = false

    var res: Boolean

    res = a and b // a.and(b)
    println("a and b = $res")

    res = a or b // a.or(b)
    println("a or b = $res")
}

In the example, we use the and() and or() functions in infix notation.

a or b = true
a and b = false

This is the output.

infix_builtin2.kt
package com.zetcode

fun main() {

    val regex = Regex("[tT]rue|[yY]es")
    val values = arrayOf("yes", "no", "YES", "True", "null", "")

    values.forEach { value ->
        if (value matches regex) println("$value matches")
        else println("$value does not match")
    }
}

In the example, we use the matches function in infix notation.

The following example creates a custom infix function.

infix_fun.kt
package com.zetcode

class Builder {

    infix fun square(n: Int) {

        for (i in 1.. n) {

            println("0".repeat(n))
        }
    }
}

fun main() {

    val builder = Builder()
    builder square 4
    println()

    builder square 6
}

The example creates an infix square function, which outputs a rectangle on the terminal.

builder square 4

We use the infix notation to call the square() function. It outputs a rectangle having width and height of four units.

In this tutorial, we have covered Kotlin functions.

List all Kotlin tutorials.