Skip to content
Related Articles

Related Articles

Function Return and Type Hierarchy in Kotlin

View Discussion
Improve Article
Save Article
Like Article
  • Difficulty Level : Medium
  • Last Updated : 20 Feb, 2022

Kotlin is a statically typed, general-purpose programming language developed by JetBrains, that has built world-class IDEs like IntelliJ IDEA, PhpStorm, App code, etc. It was first introduced by JetBrains in 2011 and is a new language for the JVM. Kotlin is an object-oriented language, and a “better language” than Java, but still be fully interoperable with Java code.

Type Hierarchy

All types of Kotlin objects are organized into a hierarchy of subtype/supertype relationships. Any is the equivalent of Java’s Object class. In Kotlin, the uppermost type is called Any. This is analogous to Java’s object type. The Any type defines the well-known toString, hashCode, and equals methods. It also defines the extension methods apply, let, and to, among others. Higher-Order Functions and Functional Programming. The Unit type is the equivalent of void in Java. Having a Unit type is common in a functional programming language, and the distinction between void and Unit is subtle. Void is not a type, but a special edge case that is used to indicate to the compiler that a function returns no value. Unit is a proper type, with a singleton instance, also referred to as Unit or ().

When a function is defined as a returning Unit, then it will return the singleton unit instance. This results in greater soundness of the type system as now all functions can be defined as having a return value, even if it’s just the Unit type, and functions that have no arguments can be defined as accepting the Unit type. Where Kotlin differs from Java most notably is the addition of a bottom type, Nothing, which is a type that has no instances. Similar to how Any is a superclass of all types, Nothing is the subclass of all types. For those who are new to the concept of a bottom type, it might seem strange to have such a type, but it has several use cases.

Firstly, Nothing can be used to inform the compiler that a function never completes normally; for example, it might loop forever, or always throw an exception. Another example is empty immutable collections. An empty list of Nothing could be assigned to a reference excepting a list of strings, and because the list is immutable, there is no danger of a string being added to such a list. Therefore, these empty values can be cached and reused. This is actually the basis of the implementation of the standard library functions emptyList(), emptySet(), and so on.

Function Return

To return a value from a function, we use the return keyword with the value or expression we want to return:

Kotlin




fun addTwoNumbers(a: Int, b: Int): Int {
  return a + b
}

Note that we specified the return value of the function. By default, return returns from the nearest enclosing function or anonymous function. So, in a nested function, this will return from the innermost function only:

Kotlin




fun largestNumber(a: Int, b: Int, c: Int): Int {
  fun largest(a: Int, b: Int): Int {
    if (a > b) return a
    else return b
  }
  return largest(largest(a, b), largest(b, c))
}

In this somewhat contrived example, the nested function largest returns only from itself. If the innermost function is an anonymous function, then that still counts for return purposes:

Kotlin




fun printLessThanTwo() {
  val list = listOf(1, 2, 3, 4)
  list.forEach(fun(x) {
    if (x < 2) println(x)
    else return
  })
  println("This line will still execute")
}

If we need to return a value from a closure, then we need to qualify the return with a label, otherwise, the return would be for the outer function. A label is just a string that ends with an @:

Kotlin




fun printUntilStop() {
  val list = listOf("a", "b", "stop", "c")
  list.forEach stop@ {
    if (it == "stop") return@stop
    else println(it)
  }
}

We don’t need to specify the label, in which case an implicit label can be used. Implicit labels are the name of the function that accepted the closure. If a label is defined, then the implicit label is not generated:

Kotlin




fun printUntilStop() {
  val list = listOf("a", "b", "stop", "c")
  list.forEach {
    if (it == "stop") return@forEach
    else println(it)
  }
}


My Personal Notes arrow_drop_up
Recommended Articles
Page :

Start Your Coding Journey Now!