DEV Community

Magda Miu
Magda Miu

Posted on • Originally published at Medium on

Kotlin functions are fun

Kotlin promises concise, expressive and safe code. In the previous articles I covered topics like basic types, control flow instructions, equality checks, null safety.

In this article we will have some fun with functions and learn new keywords from the Kotlin Wonderland.

Functions are the basic building block of any program. In Kotlin functions are declared with the fun keyword and they are first-class citizen. It means that functions can be assigned to the variables, passed as an arguments or returned from another function.

๐Ÿ“Œ Function vs. Method

Function and method are two commonly confused words. While every method is a function, not every function is a method.

A function returns a value, and a method is a function associated to an object. Function is a more general term, and all methods are also functions.

๐Ÿ“ŒGeneral syntax of a function in Kotlin

// Kotlin syntax for main function
// It returns nothing useful (Unit) and takes no arguments.

fun main() {      
   println("Hello Kotlin!")  
}     


// equivalent Kotlin syntax

fun add(a: Int, b: Int): Int {

    return a + b

}

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

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

๐Ÿ“Œ Default Arguments Functions

Kotlin supports default arguments in function declarations. A default value can be specified for a function parameter and it is used when the corresponding argument is omitted from the function call.

// default parameter values

fun displayTitleAndName(name: String, prefix: String = "dr") {

   println("$prefix $name")

}                     

๐Ÿ“Œ Named Arguments Functions

We are able to specify the names of arguments that we are passing to the function. This makes the function calls more readable. It also allows us to pass the value of a parameter selectively if other parameters have default values.

// named arguments

fun getFullName(firstName: String, lastName: String): String {

    return "$firstName $lastName"

}

getFullName(lastName = "Miu", firstName = "Magda")

๐Ÿ“Œ Infix Functions

Member functions and extensions with a single parameter can be turned into infix functions.

class Utility {

   // infix functions = functions with a single parameter

infix fun String.onto(other: String) = Pair(this, other)

}

fun main(args: Array<String>) {

    val blueShoes = "blue".onto("shoes")

    val yellowScarf = "yellow" onto "scarf"

    println(blueShoes) // => (blue, shoes)

    println(yellowScarf) // => (yellow, scarf)

}

๐Ÿ“Œ Functions with Varargs parameters

Varargs allow you to pass any number of arguments by separating them with commas.

// functions with varargs parameters

fun varargExample(vararg names: Int) {

    println("Argument has ${names.size} elements")

}

varargExample() // => Argument has 0 elements

varargExample(1) // => Argument has 1 elements

varargExample(1, 2, 3) // => Argument has 3 elements

๐Ÿ“Œ Tail Recursive Functions

  • Tail recursion is a generic concept rather than the feature of Kotlin language. Kotlin use it to optimize recursive calls.
  • In normal recursion, you perform all recursive calls first, and calculate the result from return values at last.
  • In tail recursion, calculations are performed first, then recursive calls are executed.
  • A recursive function is eligible for tail recursion if the function call to itself is the last operation it performs.
// factorial

tailrec fun factorial(n: Int, run: Int = 1): Long {

    return if (n == 1) run.toLong() else factorial(n - 1, run \* n)

}

๐Ÿ“Œ Extension Functions

  • An extension function is a member function of a class that is defined outside the class.
  • Extensions are resolved statically and can also be defined with the class type that is nullable.
  • If a class contains a companion object, then we can also define extension functions and properties for the companion object.


fun String.removeFirstLastChar(): String = this.substring(1, this.length - 1)

println("Kotlin".removeFirstLastChar()) // => otli

๐Ÿ“Œ High Order Functions

A function that can accept a function as a parameter or can return a function.

// high order function = fun with fun or fun returns a fun

fun add(a: Int, b: Int): Int {

    return a + b

}

fun returnAddFunction(): ((Int, Int) -> Int) {

    return ::add

}

๐Ÿ“Œ Operator Overloading

In Java, operators are connected to specific Java types. For example, we can use + operator in order to concatenate Strings, but no other Java type can reuse this operator for its own benefit. But Kotlin provides a set of conventions to support limited Operator Overloading.

Certain functions can be โ€œupgradedโ€ to operators, allowing their calls with the corresponding operator symbol.


// operator functions = functions "upgraded" to operators

data class IntListWrapper(val wrapped: List<Int>) {

    operator fun get(position: Int): Int = wrapped[position]

}

val listOfNumbers = IntListWrapper(listOf(1, 2, 3))

println(listOfNumbers[1]) // => 2

๐Ÿ“Œ Lambda

  • A lambda expression or an anonymous function is a โ€œfunction literalโ€, i.e. a function that is not declared, but passed immediately as an expression
  • A lambda expression is always surrounded by curly braces
  • Its parameters (if any) are declared before -> (parameter types may be omitted)
  • The body goes after -> (when present)
// returning from a lambda

val calculateGrade = { grade : Int ->

    when(grade) {

        in 0..40 -> "Fail"

        !is Int -> "Just a grade"

        in 41..70 -> "Pass"

        in 71..100 -> "Distinction"

        else -> false

     }

}

println(calculateGrade(57)) // => Pass

Enjoy and feel free to leave a comment if something is not clear or if you have questions. And if you like it please ๐Ÿ‘ and share !

Thank you for reading! ๐Ÿ™Œ๐Ÿ™๐Ÿ˜โœŒ

Follow me on Twitter Magda Miu

Top comments (0)