Kotlin Functions

A function is a block of code that only runs when it is called.


There are two types of functions:

  • Standard library function,
  • User-defined function.

You can pass data, known as parameters, into a function.

Functions are used to perform certain actions, and they are also known as methods.

Standard library function:

Kotlin Standard library function is a built-in library function that is implicitly present in the library and available for use.

  • Here, sqrt() is a library function which returns square root of a number (Double value).
  • print() library function which prints a message to standard output stream.

fun main(args: Array<String>){  
var number = 25
var result = Math.sqrt(number.toDouble())
print("Square root of $number is $result")
}
Output:
Square root of 25 is 5.0

User-defined Function:

A user-defined function is a function that is created by the user. The user-defined function takes the parameter(s), performs an action, and returns the result of that action as a value.

  • To create your own function, use the fun keyword, and write the name of the function, followed by parantheses ():
  • To call a function in Kotlin, write the name of the function followed by two parantheses ().
fun main() {
myFunction() // Call myFunction
}

// Outputs "I just got executed!"


Function Parameters:

Information can be passed to functions as parameters.

Parameters are specified after the function name, inside the parentheses. You can add as many parameters as you want, just separate them with a comma. Just note that you must specify the type of each parameter (Int, String, etc).

fun myFunction(fname: String) {
println(fname + " Doe")
}

fun main() {
myFunction("John")
myFunction("Jane")
myFunction("George")
}

// John Doe
// Jane Doe
// George Doe


Default Argument:

Kotlin provides a facility to assign a default argument (parameter) in a function definition.

Default argument example 1: passing no argument in the function call

fun main(args: Array<String>) {  
run()
}
fun run(num:Int= 5, latter: Char ='x'){
print("parameter in function definition $num and $latter")
}

Output:
parameter in function definition 5 and x

In the above program, run() function calls with no argument, the default parameter is used in the function definition.

Default argument example 2: passing some argument in the function call

fun main(args: Array<String>) {  
run(3)
}
fun run(num:Int= 5, latter: Char ='x'){
print("parameter in function definition $num and $latter")
}
Output:
parameter in function definition 3 and x

In the above program, run() function calls with one (first) argument, the first parameter of the function definition uses the value passed to the function. And the second parameter is used as a default argument.

Default argument example 3: passing all arguments in function call

fun main(args: Array<String>) {  
run(3,'a')
}
fun run(num:Int= 5, latter: Char ='x'){
print("parameter in function definition $num and $latter")
}
Output:
parameter in function definition 3 and a

As all the arguments are passed in run() function call, the parameters of function definition use the argument passed in the function call.

Named Argument:

Eg: Here, we are trying to pass parameter 'a' from function call to function definition in the second argument. But compiler assumes that the parameter 'a' (Char type) passed for the first argument (Int type) this causes an error in the program.

To solve the above problem a named argument is used.

A named argument is an argument in which we define the name of the argument in the function call. The name defined to the argument of the function call checks the name in the function definition and assigns it to it.

fun main(args: Array<String>) {  

run('a') // Error: Kotlin: The character literal does not conform to the expected type Int
run(latter='a') //Success: parameter in function definition 5 and a
}
fun run(num:Int= 5, latter: Char ='x'){
print("parameter in function definition $num and $latter")
}


Lambda Function:

Lambda is a function that has no name. Lambda is defined with a curly brace {} which takes a variable as a parameter (if any) and the body of the function. The body of the function is written after the variable (if any) followed by -> operator.

Syntax :{ variable -> body_of_function}  

Lambda function: addition of two numbers

Eg:

fun main(args: Array<String>){  
val myLambda: (Int) -> Unit= {s: Int -> println(s) } //lambda function
addNumber(5,10,myLambda)
}
fun addNumber(a: Int, b: Int, mylambda: (Int) -> Unit ){ //high level function lambda as parameter
val add = a + b
mylambda(add) // println(add)
}
Output: 15

In the above program we create a lambda expression {s: Int -> println(s) } with its return type Unit. The lambda function is padded as an parameter in high level function addNumber(5,10,myLambda). The variable mylambda in function definition is actually a lambda function. The functionality (body) of mylambda is already given in lambda function.


Higher-order function:

(Higher level function) is a function that accepts a function as a parameter or returns a function or can do both. This means, that instead of passing Int, String, or other types as a parameter in a function we can pass a function as a parameter in another function.

We defined a function myFun() with three parameters. The first and second parameters take String and the third parameter as a type of function from String to String. The parameter String to String type means the function takes a string as an input and returns the output as string types.

To call this the above function, we can pass function literal or lambda. For example:

fun myFun(name1: String,name2: String, fn: (String,String) -> String): Unit {  
val result = fn(name1,name2)
println(result)
}

fun main(args: Array<String>){
val fn:(String,String)->String={name1,name2->"$name1 and $name2"}
myFun("hari"," sakthi",fn)
}
Output:
hari and sakthi


Inline Function

An inline function is declared with a keyword inline. The use of the inline function enhances the performance of the higher-order function.

One of them is high order functions which let you pass functions as parameters as well as return functions. But the fact that they are stored as objects may make the use disadvantageous at times because of the memory overhead. The thing is, each object is allocated space in the memory heap, and the methods that call this method are also allocated space. Check out a high order function in below snippet:

fun main(args: Array<String>) {
var a = 2
println(someMethod(a, {println("Just some dummy function")}))
}
fun someMethod(a: Int, func: () -> Unit):Int {
func()
return 2*a
}

A way to get around the memory overhead issue is, by declaring the function inline. inline annotation means that function, as well as function parameters, will be expanded at the call site which means it helps reduce call overhead. 

Declaring a function inline is simple, just add inline keyword to the function like in the below code snippet 

inline fun someMethod(a: Int, func: () -> Unit):Int {
func()
return 2*a
}

So basically inline can be used when we wish to reduce memory overhead. But inline also increases the resulting bytecode. This is why inline usage should be avoided with large functions or accessors with large code logic.


Comments