The base of Kotlin's class hierarchy
Any, Unit & Nothing Kotlin Generics Explained
Every programming language has some hierarchy for its classes and Kotlin is no exception. Let’s dive into the concepts:
Unit
This is the one you’ll probably see the most. In the standard library, it’s defined as:
public object Unit {
override fun toString() = "kotlin.Unit"
}
For Java programmers, it’ll be easy to think of it as of void
, but it’s an object
not a keyword. It means ‘nothing is returned’. It’s your default function return type:
// This function return Unit
fun doSomething() {}
It also means that the function is completed. It can be used in generics for functions that don’t return any data:
interface GenericInterface<out T> {
fun doSomething(): T
}
class NoValueClass : GenericInterface<Unit> {
override fun doSomething() {}
}
fun main() {
val noValueClass = NoValueClass()
// Compiler is not saying we're swalling the return because we use Unit
noValueClass.doSomething()
}
It’s useful in functional programming. It’s commonly used in lambdas:
val hello: () -> Unit = { println("Hello") }
Any
In Kotlin every class inherits from Any
, think of it as a Base class for classes. It looks like this in the standard library:
public open class Any {
public open operator fun equals(other: Any?): Boolean
public open fun hashCode(): Int
public open fun toString(): String
}
It’s useful in that you can write very generic algorithms that compare stuff with equals
as well as transform data into Int
with hashCode
.
There is not much more to it, recognizing it exists might prove useful at some point.
Nothing
This type represents a “value that never exists”. It’s the opposite of Any
and stands at the bottom of the class hierarchy. The code in standard library looks like this:
public class Nothing private constructor()
The constructor is private
meaning you won’t be able to create a new instance of type Nothing
. It can be used for functions that never return something. For example, a function with an infinite loop:
fun doForever(): Nothing {
while (true) {
println("stuck forever")
}
}
It can be used for performance reasons and to limit usage of an object. For example when using emptyList
,emptyMap
etc. you’re using Nothing
:
public fun <T> emptyList(): List<T> = EmptyList
object EmptyList : List<Nothing>