Kotlin Functions, Default and Named Arguments, Varargs and Function Scopes
KotlinMarch 03, 20184 mins readFunctions are the basic building block of any program. In this article, you’ll learn how to declare and call functions in Kotlin. You’ll also learn about Function scopes, Default arguments, Named Arguments, and Varargs.
Defining and Calling Functions
You can declare a function in Kotlin using the fun
keyword. Following is a simple function that calculates the average of two numbers -
fun avg(a: Double, b: Double): Double {
return (a + b)/2
}
Calling a function is simple. You just need to pass the required number of parameters in the function name like this -
avg(4.6, 9.0) // 6.8
Following is the general syntax of declaring a function in Kotlin.
fun functionName(param1: Type1, param2: Type2,..., paramN: TypeN): Type {
// Method Body
}
Every function declaration has a function name, a list of comma-separated parameters, an optional return type, and a method body. The function parameters must be explicitly typed.
Single Expression Functions
You can omit the return type and the curly braces if the function returns a single expression. The return type is inferred by the compiler from the expression -
fun avg(a: Double, b: Double) = (a + b)/2
avg(10.0, 20.0) // 15.0
Note that, Unlike other statically typed languages like Scala, Kotlin does not infer return types for functions with block bodies. Therefore, Functions with block body must always specify return types explicitly.
Unit returning Functions
Functions which don’t return anything has a return type of Unit
. The Unit
type corresponds to void
in Java.
fun printAverage(a: Double, b: Double): Unit {
println("Avg of ($a, $b) = ${(a + b)/2}")
}
printAverage(10.0, 30.0) // Avg of (10.0, 30.0) = 20.0
Note that, the Unit
type declaration is completely optional. So you can also write the above function declaration like this -
fun printAverage(a: Double, b: Double) {
println("Avg of ($a, $b) = ${(a + b)/2}")
}
Function Default Arguments
Kotlin supports default arguments in function declarations. You can specify a default value for a function parameter. The default value is used when the corresponding argument is omitted from the function call.
Consider the following function for example -
fun displayGreeting(message: String, name: String = "Guest") {
println("Hello $name, $message")
}
If you call the above function with two arguments, it works just like any other function and uses the values passed in the arguments -
displayGreeting("Welcome to the CalliCoder Blog", "John") // Hello John, Welcome to the CalliCoder Blog
However, If you omit the argument that has a default value from the function call, then the default value is used in the function body -
displayGreeting("Welcome to the CalliCoder Blog") // Hello Guest, Welcome to the CalliCoder Blog
If the function declaration has a default parameter preceding a non-default parameter, then the default value cannot be used while calling the function with position-based arguments.
Consider the following function -
fun arithmeticSeriesSum(a: Int = 1, n: Int, d: Int = 1): Int {
return n/2 * (2*a + (n-1)*d)
}
While calling the above function, you can not omit the argument a
from the function call and selectively pass a value for the non-default parameter n
-
arithmeticSeriesSum(10) // error: no value passed for parameter n
When you call a function with position-based arguments, the first argument corresponds to the first parameter, the second argument corresponds to the second parameter, and so on.
So for passing a value for the 2nd parameter, you need to specify a value for the first parameter as well -
arithmeticSeriesSum(1, 10) // Result = 55
However, The above use-case of selectively passing a value for a parameter is solved by another feature of Kotlin called Named Arguments.
Function Named Arguments
Kotlin allows you to specify the names of arguments that you’re passing to the function. This makes the function calls more readable. It also allows you to pass the value of a parameter selectively if other parameters have default values.
Consider the following arithmeticSeriesSum()
function that we defined in the previous section -
fun arithmeticSeriesSum(a: Int = 1, n: Int, d: Int = 1): Int {
return n/2 * (2*a + (n-1)*d)
}
You can specify the names of arguments while calling the function like this -
arithmeticSeriesSum(n=10) // Result = 55
The above function call will use the default values for parameters a
and d
.
Similarly, you can call the function with all the parameters like this -
arithmeticSeriesSum(a=3, n=10, d=2) // Result = 120
You can also reorder the arguments if you’re specifying the names -
arithmeticSeriesSum(n=10, d=2, a=3) // Result = 120
You can use a mix of named arguments and position-based arguments as long as all the position-based arguments are placed before the named arguments -
arithmeticSeriesSum(3, n=10) // Result = 75
The following function call is not allowed since it contains position-based arguments after named arguments -
arithmeticSeriesSum(n=10, 2) // error: mixing named and positioned arguments is not allowed
Variable Number of Arguments (Varargs)
You can pass a variable number of arguments to a function by declaring the function with a vararg
parameter.
Consider the following sumOfNumbers()
function which accepts a vararg of numbers -
fun sumOfNumbers(vararg numbers: Double): Double {
var sum: Double = 0.0
for(number in numbers) {
sum += number
}
return sum
}
You can call the above function with any number of arguments -
sumOfNumbers(1.5, 2.0) // Result = 3.5
sumOfNumbers(1.5, 2.0, 3.5, 4.0, 5.8, 6.2) // Result = 23.0
sumOfNumbers(1.5, 2.0, 3.5, 4.0, 5.8, 6.2, 8.1, 12.4, 16.5) // Result = 60.0
In Kotlin, a vararg
parameter of type T
is internally represented as an array of type T
(Array<T>
) inside the function body.
A function may have only one vararg
parameter. If there are other parameters following the vararg
parameter, then the values for those parameters can be passed using the named argument syntax -
fun sumOfNumbers(vararg numbers: Double, initialSum: Double): Double {
var sum = initialSum
for(number in numbers) {
sum += number
}
return sum
}
sumOfNumbers(1.5, 2.5, initialSum=100.0) // Result = 104.0
Spread Operator
Usually, we pass the arguments to a vararg
function one-by-one. But if you already have an array and want to pass the elements of the array to the vararg
function, then you can use the spread operator like this -
val a = doubleArrayOf(1.5, 2.6, 5.4)
sumOfNumbers(*a) // Result = 9.5
Function Scope
Kotlin supports functional programming. Functions are first-class citizens in the language.
Unlike Java where every function needs to be encapsulated inside a class, Kotlin functions can be defined at the top level in a source file.
In addition to top-level functions, you also have the ability to define member functions, local functions, and extension functions.
1. Top Level Functions
Top level functions in Kotlin are defined in a source file outside of any class. They are also called package level functions because they are a member of the package in which they are defined.
The main()
method itself is a top-level function in Kotlin since it is defined outside of any class.
Let’s now see an example of a top-level function. Check out the following findNthFibonacciNo()
function which is defined inside a package named maths
-
package maths
fun findNthFibonacciNo(n: Int): Int {
var a = 0
var b = 1
var c: Int
if(n == 0) {
return a
}
for(i in 2..n) {
c = a+b
a = b
b = c
}
return b
}
You can access the above function directly inside the maths
package -
package maths
fun main(args: Array<String>) {
println("10th fibonacci number is - ${findNthFibonacciNo(10)}")
}
//Outputs - 10th fibonacci number is - 55
However, If you want to call the findNthFibonacciNo()
function from other packages, then you need to import it as in the following example -
package test
import maths.findNthFibonacciNo
fun main(args: Array<String>) {
println("10th fibonacci number is - ${findNthFibonacciNo(10)}")
}
2. Member Functions
Member functions are functions which are defined inside a class or an object.
class User(val firstName: String, val lastName: String) {
// Member function
fun getFullName(): String {
return firstName + " " + lastName
}
}
Member functions are called on the objects of the class using the dot
(.) notation -
val user = User("Bill", "Gates") // Create an object of the class
println("Display Name : ${user.getFullName()}") // Call the member function
3. Local/Nested Functions
Kotlin allows you to nest function definitions. These nested functions are called Local functions. Local functions bring more encapsulation and readability to your program -
fun findBodyMassIndex(weightInKg: Double, heightInCm: Double): Double {
// Validate the arguments
if(weightInKg <= 0) {
throw IllegalArgumentException("Weight must be greater than zero")
}
if(heightInCm <= 0) {
throw IllegalArgumentException("Height must be greater than zero")
}
fun calculateBMI(weightInKg: Double, heightInCm: Double): Double {
val heightInMeter = heightInCm / 100
return weightInKg / (heightInMeter * heightInMeter)
}
// Calculate BMI using the nested function
return calculateBMI(weightInKg, heightInCm)
}
Local functions can access local variables of the outer function. So the above function is equivalent to the following -
fun findBodyMassIndex(weightInKg: Double, heightInCm: Double): Double {
if(weightInKg <= 0) {
throw IllegalArgumentException("Weight must be greater than zero")
}
if(heightInCm <= 0) {
throw IllegalArgumentException("Height must be greater than zero")
}
// Nested function has access to the local variables of the outer function
fun calculateBMI(): Double {
val heightInMeter = heightInCm / 100
return weightInKg / (heightInMeter * heightInMeter)
}
return calculateBMI()
}
Conclusion
Congratulations folks! In this article, you learned how to define and call functions in Kotlin, how to use default and named arguments, how to define and call functions with a variable number of arguments, and how to define top-level functions, member functions and local/nested functions
In future articles, I’ll write about extension functions, higher order functions and lambdas. So Stay tuned!
As always, Thank you for reading. Happy Kotlin Koding :)