Kotlin Functions

Filed Under: Kotlin

In this tutorial, we’ll be discussing at length, Functions in Kotlin. We’ll discuss everything you need to know about kotlin functions right from the syntax to the various implementations.

Kotlin Functions

kotlin functions

In Kotlin, functions can be used at the top level. By top level, we mean they can be defined without the need to be enclosed in a class or anywhere. This is one of the primary reasons that in Kotlin, we use the term functions instead of methods.

Types of Functions

Functions can be defined into various types depending on the various categories. At a very high level, we define the function in the following two categories.

By Scope

  • Top Level Functions: These do not need a class to be enclosed in.
  • Member Functions: These are defined inside a class or Object
  • Local or Nested Functions: Functions that are defined in another function fall into this type.

By definition

  • Kotlin Standard Functions: Kotlin has its own set of functions such as main(), println() etc. defined in the standard library
  • User defined functions: Which we write in our projects.

Kotlin Function Basic Syntax

Functions in Kotlin are fun! No doubt a function is defined using the keyword fun. It is followed by the function name. The parameters along with their types go inside the brackets. The return type is set outside the brackets as shown below.

fun function_name(param1: Type1, param2: Type2,.....) : SetReturnTypeHere{
    //function body goes here.
}

Note: To override a function in subclasses we need to append the modifier override

Declarations and Usage

Let us define a function that calculates the sum of two numbers. We’ll do this in each of the types defined by scope.

  • Top Level Functions
    fun main(args: Array<String>) {
        
        sumOfTwo(2,3) //returns 5
    
    
    }
    
    fun sumOfTwo(a: Int, b: Int): Int{
    
        return a + b
    }
    

    To call the function we just need to pass the parameters as the arguments.

  • Member Functions
    Member Functions are defined inside a class. A member function is invoked over the instance of the class using a dot operator as shown in the below code.

    fun main(args: Array<String>) {
    
        var a = A()
        a.sumOfTwo(2,3)
    
    }
    
    class A {
    
        fun sumOfTwo(a: Int, b: Int): Int{
    
            return a + b
        }
        
    }
    
  • Local/Nested Functions
    We can define a function inside another function. It can also be a return type of the enclosing function.
    The below code demonstrates the same.

    fun main(args: Array<String>) {
    
    
         sumOfDoubleOfTwo(2,3) //returns 5
         print(sumOfDoubleOfTwo(2,3)) //prints 10. This is a triple nested function.
    
    }
    
    
    fun sumOfDoubleOfTwo(a: Int, b: Int): Int {
    
    
        fun letMeDoubleAndAdd(): Int {
            return a * 2 + b * 2
        }
    
        return letMeDoubleAndAdd()
    }
    

    letMeDoubleAndAdd() does the execution part and returns the result to the first function.
    Note: The print function in the above code implicitly encloses the sumOfDoubleOfTwo() function. Hence the sumOfDoubleOfTwo() acts as a nested function in the second statement.

Unit-Returning Types

If there’s no return type, we can leave the return type space empty.

fun main(args: Array<String>) {

    helloWorld() //prints Fun says hello world
    print(helloWorld()) //prints Fun says hello world\nkotlin.Unit

}

fun helloWorld() {
    println("Fun says hello world")
}

What’s kotlin.Unit?
Unit is the Kotlin equivalent of void in Java.
So the above function can also be written as :

fun helloWorld() :Unit {
    println("Fun says hello world")
}

We can stay away from the above definition though since setting the Unit return type is not compulsory.

Default and Named Arguments

Kotlin allows setting default values in the function definition. This way, if you don’t pass an argument in the function call, the default value would be used as shown below.

fun main(args: Array<String>) {

    print(appendAllParams("Hi", message = "How are you doing?")) //prints Hi Jay, How are you doing?

}

fun appendAllParams(greet: String, name: String = "Jay", message: String): String {
    return greet + name + ", " + message
}

Named Arguments lets us set the name of the parameter to the respective argument in in the function call.
This way instead of always sticking to the defined order of parameters, we can set our own order.
It enhances the readability of the function too as shown below.

fun main(args: Array<String>) {

    returnBooleans(a = true, b = true, c = true, d = false)
}

fun returnBooleans(a: Boolean, b: Boolean, c: Boolean, d: Boolean): Boolean {
    return a && b || c && d
}

In the above code, we’re able to keep a track of each parameter name and value in the function unlike the following code where we can forget which argument is set for which parameter.

returnBooleans(true, true, true, false)

Single Expression Functions

Functions in Kotlin that consist of a single expression only can be made much simpler and concise using the following syntax:

fun main(args: Array<String>) {

    print(sumOfTwo(2, 3))
}

fun sumOfTwo(a: Int, b: Int) = a + b

As shown above, single expressions can be written on the Right hand side of =.
Single expression functions do not require setting the return type or the curly braces. Kotlin automatically infers it for you.

Variable Number of Arguments – varargs

We can define functions in Kotlin with a variable number of arguments using the vararg modifier in the parameter declaration as shown below.

fun main(args: Array<String>) {
    print(concatenate("Hello\n", "How are you doing?\n", "Add more words in here\n"))
}

fun concatenate(vararg word: String): String {

    var result = ""

    for (s in word) {
        result += s
    }

    return result
}

Only one vararg parameter is allowed her function.

Functions as Types

In Kotlin we can use functions as types and assign it to properties, pass them as arguments in other functions or use them as return values(High Order Functions).

fun main(args: Array<String>) {
    val str = concatenate("Hello\n", "How are you doing?\n", "Add more words in here\n") 
    //str is of type String
}

fun concatenate(vararg word: String): String {

    var result = ""

    for (s in word) {
        result += s
    }

    return result
}

Function types is a powerful concept and we’ll look at it in detail in High Order Functions.

Spread Operator

A spread operator is denoted by * and is decomposes an array into individual elements which we’ll eventually pass into the vararg parameter as shown below.

fun main(args: Array) {
    val a = intArrayOf(1, 2, 3)
    print(sumOfNumbers(*a))

}

fun sumOfNumbers(vararg numbers: Int): Int {
    var sum = 0
    for (number in numbers) {
        sum += number
    }
    return sum
}

intArrayOf creates an array out of the elements which is passed into the sumOfNumbers function that’ll eventually spread the array into a vararg.

Extension Functions

Extension Functions are used to extend some functionality to a class .

fun main(args: Array<String>) {
    var x = 5


    print(x.multiplyByTwo()) //10
}

fun Int.multiplyByTwo() : Int
{
  return this*2
}

In classes
We can always extend a function from a class as shown below:

fun main(args: Array<String>) {
    val b = Book()
    b.printFunction("Hey") //member function
    b.printFunction() //extension function
}

fun Book.printFunction()
{
    println("Extension")
}

class Book {
    fun printFunction(str: String) {
        println(str)
    }
}

//Following is printed on the console
//Hey
//Extension

In the above code, the extension function overloads the member function from the class.

Infix Notations

Infix notations are added on a function to make the function calling more cleaner and closer to the english language since we don’t need to call the function using a dot notation as we’ll be seeing shortly.
Requirements:

  • Add the infix modifier before the function keyword
  • Its only applicable on a member or extension function
  • An infix function can have only one parameter

An example below demonstrates the same.

fun main(args: Array<String>) {
    val b = Numbers()
    b addNumber 5

    print(b.x) //prints 15
}


class Numbers {

    var x = 10
    infix fun addNumber(num: Int) {
        this.x = this.x + num
    }
}


From the above code, we can decipher that bitwise operator and, or etc are infix functions in kotlin.
Also, infix notation function is used in downTo, until etc in loops in Kotlin too

Tail Recursive Functions

Tail Recursive Functions is a template that Kotlin uses to get rid of the loops in recursive functions.
Adding the tailrec modifier to a function would write the function as a recursive one without for/while loops hence decreasing the risk of stack overflow.
Typically we can write recursive functions like this:

fun findFixPoint(): Double {
    var x = 1.0
    while (true) {
        val y = Math.cos(x)
        if (x == y) return x
        x = y
    }
}

Using tailrec the above function should look like this:

tailrec fun findFixPoint(x: Double = 1.0): Double
        = if (x == Math.cos(x)) x else findFixPoint(Math.cos(x))

Note: tailrec is only valid when there is no code after the recursive call.

Creating a Factorial Tail Recursive Function

Typically a factorial function is written like this:

fun factorial(n: Long, accum: Long = 1): Long {
    val soFar = n * accum
    return if (n <= 1) {
        soFar
    } else {
        factorial(n - 1, soFar)
    }
}

The tail recursive function would look like:

fun main(args: Array<String>) {
    var x =calculateFact(1,5)
    print(x)
}

tailrec fun calculateFact(acc: Long, n: Long): Long {
    if (n == 1L) {
        return acc
    }
    return calculateFact(n * acc, n - 1)
}

We’ve covered the basics of Functions in Kotlin in this tutorial. We’ll be looking at High Order Functions, Anonymous Functions, Inline Functions and many more things in the upcoming tutorials.

References : Kotlin Docs

Comments

  1. Ali says:

    Hi ,
    Here are a note on extension functions in kotlin, extension funs for class methods (member funs) are used to add new member function to a class and this function should has its own name. You said that functions used to extend class member function and this is not correct.
    I highly appreciate how comprehensive kotlin’s tutorials on you website and will be back to learn more .
    Reguards
    Ali 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages