Functions in Kotlin (part 2)

Tanvi Goyal
Kotlin Classes
Published in
6 min readMay 31, 2020

--

This is Part II of the series — Getting Started with Kotlin. If you haven’t yet, please check Part I on basic fundamentals.

This article will cover the basics of functions -

  • Function Declaration
  • Types of Functions
  • Default Arguments
  • Named Arguments
  • Single Expression functions
  • Unit Functions
  • Variable number of arguments — varargs
  • Infix Notation

You can also find the source code of these examples at -

Functions in general is a section of a program that performs a specific task.

  1. Function Declaration

Functions are declared with a fun keyword, followed by the function name, parameters to be passed, and the return type of the function. The basic syntax of a function is

fun function_name(param1: Type1, param2: Type2,…..) : return_type {
}

To override a function, we need to use the override keyword also before fun.

override fun function_name(param1: Type1, param2: Type2,…..) : return_type {
}

Function parameters are defined using Pascal notation i.e paramName : paramType.

2. Types of Functions

Functions in Kotlin can be classified into 3 main categories.

a) Top-Level Functions

Kotlin allows functions to be declared at the top level of the file, i.e, it is not mandatory to create a class to hold a function. As the name suggests, they are not nested inside any structure and are at the top level of the hierarchy of classes and functions. They are helpful for defining helper or utility functions.

b) Member Functions

Member Functions is a function that can be defined inside a class or object and called with a dot(.) operator, same as we do in Java.

c) Local/Nested Functions

As the name suggests, Local or Nested Functions are function inside another function and they can access the local variables of outer functions.

private fun nestedFun(height: Int, width: Int) { val breadth = height * 2; fun getVolume(height: Int, width: Int): Int {
return height * width * breadth
}
getVolume(height, width)
}

3. Default Arguments

As the name suggests, we can pass default values to parameters that are used when we do not give any value to that parameter while calling the function.

private fun getVolume(height: Int, width: Int, breadth :Int = 10) : Int {
return height * width * breadth;
}

By setting a default value to the breadth parameter, we can call this function in 2 ways. If we only specify values for length and width, it will take the default value of breadth i.e 10 but if we specify the value for breadth also while function call, it will take the passed value i.e 15.

getVolume(20, 10)
getVolume(20, 10, 15)

But if the default value precedes the parameter with no default value, then the default value can only be used by calling the function with named parameters. We will talk about them later in this article.

private fun getVolume(height: Int, breadth :Int = 10 , width: Int) : Int {
return height * width * breadth;
}

Function calling would now be like -

getVolume(20, width = 10)

We cannot pass default values when overriding a method that has default parameter values. Consider a class Box having a function getVolume() and its subclass Rectangle -

open class Box {
open fun getVolume(height: Int, width: Int, breadth :Int = 10 ) { }
}
class Rectangle : Box() { override fun getVolume(height: Int, width: Int, breadth: Int) {
super.getVolume(height, width, breadth)
}
}

If we try to pass the default value to the parameter breadth, it will result in a compile-time error.

4. Named Arguments

Kotlin allows naming the arguments of the function. One usage of that we saw above using default arguments. Other than that, when we have a larger number of parameters of a function, it enhances code readability also.

getVolume(height = 20, breadth = 10, width = 15)

But if the named argument is mixed with positioned arguments, first all positioned arguments should come followed by named arguments. The code below shows the example -

getVolume(20, breadth = 10, width = 15)

Changing it to the below format would result in an error -

5. Single Expression Functions

For single expressions in a function, Kotlin allows omitting the curly braces and the return keyword, and directly specifying the body after the = sign.

fun getVolume(height: Int, breadth :Int = 10 , width: Int) = height * width * breadth

6. Unit Functions

Every function in Kotlin returns something, even when nothing is explicitly defined. It then returns a type kotlin.Unit

Unit in Kotlin is like void in Java.

val isUnit = printVolume(20, 10,15)
println(isUnit)
private fun printVolume(height: Int, breadth: Int, width: Int) {
println(height * breadth * width)
}

The output of the above code would be -

3000
kotlin.Unit

7. Variable number of arguments — varargs

For declaring a variable number of arguments, we can use the varargs keyword with the parameter name.

varargUsage(1,2,3,4)private fun varargUsage(vararg params: Int) : Int{
var volume = 1;
for (value in params) {
volume += value
}
return volume
}

Only one vararg parameter is allowed in the function and if it is not the last parameter, then we can only call the function using named arguments.

varArgUsage(1, 2, 3, str = “Volume of the box is”)fun varArgUsage(vararg params: Int, str: String) {
var volume = 1;
for (value in params) {
volume += value
}
println(“$str $volume”)
}

Spread Operator (*) — We can also pass the value of vararg params without writing them one by one. In cases where we have already created an array and we need to pass all the values of that array, we can simply pass the whole array using * before the array name.

val arr = intArrayOf(1, 2, 3)
varArgUsage(*arr, str = “Volume of the box is”)

8. Infix Notation

Infix notation means omitting the dot and the parenthesis used to call the function i.e

private infix fun infixUsage(height: Int): Int = height

can be called as

this infixUsage 10

There are certain conditions for a function to be an infix function -

i) It should be declared with the infix keyword.

ii) It should have only one parameter.

iii) It should be a member function or an extension function.

iv) The parameter of the infix function should not accept a variable number of. arguments or have a default value.

v) It should have both the receiver and the parameter to be specified. In the above example, we have to explicitly declare this as a receiver to ensure ambiguous parsing.

Conclusion

In this article, we explored the basics of functions and how they work in Kotlin. We studied various ways of defining and calling functions by default, named and a variable number of arguments followed by Unit and infix functions Kotlin offers.

There is a lot more that we will cover in upcoming articles.

  1. Part 3 - Generics in Kotlin

If you like this article, don’t forget to clap and to keep up-to-date with all my new articles, you can follow me and my publication on Medium.

Any feedback, suggestions are always welcomed and appreciated!

Keep Learning!

Tanvi Goyal

--

--