Kotlin - Void vs. Unit vs. Nothing - kotlin

Kotlin has three types that are very similar in nature:
Void
Unit
Nothing
It almost seems like they're making the JavaScript mistake:
null
undefined
void(0)
Assuming that they haven't fallen into the same mistake, what are they all for, and how do they differ?

The Void type is from Java. You generally won't use this from Kotlin unless you're using some Java-library that uses it.
The Unit type is what you return from a function that doesn't return anything of interest. Such a function is usually performing some kind of side effect. The unit type has only one possible value, which is the Unit object. You use Unit as a return type in Kotlin when you would use void (lowercase v) in Java.
The Nothing type has no values. If a function has return type Nothing, then it cannot return normally. It either has to throw an exception, or enter an infinite loop. Code that follows a call to a function with return type Nothing will be marked as unreachable by the Kotlin compiler.
Because Nothing has no values, Nothing? is actually the type that captures only the null value in Kotlin.

Unit
Unit is like void
In Kotlin, when a function does not return any meaningful value, it is declared to return Unit, just like void in Java:
fun greet(): Unit { println("Good day!") }
It's a convention to skip writing Unit when a function returns Unit because Unit is considered the default return type by the compiler:
fun greet() { println("Good day!") }
Unit is a Singleton
The Unit is a class with only a single object (singleton pattern) and that object is the Unit itself. It is declared in the kotlin package using an object declaration as shown below:
public object Unit {
override fun toString() = "kotlin.Unit"
}
Unit in Functional Programming
Kotlin has first-class support for functional programming. It's common to have a Unit in a functional programming language. It makes the function types more readable by enabling all the functions to be declared as having a return value, even when a function does not return a value:
val greet: () -> Unit = { println("Good day!") }
Here, () -> Unit is a function type and the Unit after the -> indicates that this function type does not return any meaningful value. Mentioning the Unit cannot be skipped in function types.
Unit for Extending Generics
Every function has to return a value. Kotlin decided to represent this with a class rather than with a special type void as in Java. The reason for using a class is that the type system can be made more consistent by making it a part of the type hierarchy.
For example, let's say we have a generic interface called Worker<T> that performs some work. The doWork() function of this interface does some work and has to return a value T:
interface Worker<T> {
fun doWork(): T
}
But sometimes, we might want to use this interface for some work where we don't need to return any value, for example, the work of logging, in the LogWorker class shown below that extends the Worker interface:
class LogWorker : Worker<Unit> {
override fun doWork() {
// Do the logging
}
}
This is the magic of Unit where we are able to use the pre-existing interface that was originally designed to return a value. Here we make the doWork() function return the Unit value to serve our purpose in which we don't have anything to return. So, it's useful when you override a function that returns a generic parameter.
Notice that we have also skipped mentioning Unit return type for the doWork() function. There's no need to write a return statement either.
Nothing
Nothing's Value Never Exists
In Kotlin, the class Nothing represents a value that never exists. There can never be any value/object of this class because its constructor is kept private. It's defined in the kotlin package as follows:
public class Nothing private constructor()
Nothing is used for the return type of a function that never returns a value. For example, a function with an infinite loop or a function that always throws an exception. The error() function from Kotlin standard library is an example that always throws an exception and returns Nothing. Here is the code for it:
fun error(message: Any): Nothing = throw IllegalStateException(message.toString())
Nothing is the Bottom Type
In type theory, the type that has no values is called a bottom type and it is a subtype of all other types. So, Nothing is the subtype of all types in Kotlin, just like Any? is the supertype of all types. So, the value(that never exists) of type Nothing is assignable to the variables of all types, for example:
val user: User = request.user ?: error("User not found")
Here, we are calling the error() function that we defined earlier, if the user is null, using the elvis operator(?:). The error() function returns the value of type Nothing but it can be assigned to the variable of type User because Nothing is a subtype of User, just like it is a subtype of any other type. The compiler allows this because it knows that the error() function will never return a value, so there is no harm.
Similarly, you can return Nothing from a function that has any other return type:
fun getUser(request: Request): User {
return request.user ?: error("User not found")
}
Here, even though the getUser() function is declared to return a User, it may return Nothing, if the user is null.
Nothing in Null Object Pattern
Consider the following example of a function that deletes the files given in a list:
fun deleteFiles(files: List<File>? = null) {
if (files != null) files.forEach { it.delete() }
}
The problem with the design of this function is that it doesn't convey whether the List<File> is empty or null or has elements. Also, we need to check whether the list is null before using it.
To solve this problem, we use the null object design pattern. In null object pattern, instead of using a null reference to convey the absence of an object, we use an object which implements the expected interface, but leaves the method body empty.
So, we define the object of the interface List<Nothing>:
// This function is already defined in the Kotlin standard library
fun emptyList() = object : List<Nothing> {
override fun iterator(): Iterator<Nothing> = EmptyIterator
...
}
Now we use this null object in our deleteFiles() function as a default value of our parameter:
fun deleteFiles(files: List<File> = emptyList()) {
files.forEach { it.delete() }
}
This removes the uncertainty of null or empty and makes the intent clearer. It also removes the null checks because the functions on the null object are empty, they will be called but they are no-ops (no operation in them, so they will do nothing).
Nothing for Covariant Generics
In the example above, the compiler allows us to pass List<Nothing> where List<File> is expected. This is because the List interface in Kotlin is covariant since it's defined using the out keyword, that is, List<out T>. And as we learnt, Nothing is a subtype of all types, Nothing is a subtype of File too. And due to covariance, List<Nothing> is a subtype of List<File>, List<Int>, List<User> and so on... List<AllTypes>. This applies to any type with the covariant generics(out), not just List.
Nothing for Better Performance
Just like the function emptyList() used in our example, there are predefined functions like emptyMap(), emptySet(), emptySequence() that return null objects. All these are defined using Nothing. You can define your own objects like this.
The advantage here is that these return singleton objects, for example, you can call the same emptyList() function for getting an empty instance, whether it is for assigning to List<File>, List<Int> and ... List<AllTypes> and in multiple places. Since the same object is returned every time, it saves the cost of object creation and memory allocation.
Void
Void for Extending Generics in Java
The Void class is from the java.lang package while the Unit and Nothing are from the kotlin package. Void is not intended to be used in Kotlin. Kotlin has its own class in the form of Unit.
Void is used in Java for extending generic interfaces like our Worker interface example written for Unit where we have to return a value. So for converting our Kotlin code to Java, we can use Void the same way we have used Unit for our Worker example and rewrite the code in Java as follows:
interface Worker<T> {
T doWork();
}
class LogWorker implements Worker<Void> {
#Override public Void doWork() {
// Do the logging
return null;
}
}
Notice that when using Void, we have to use Void as a return type(can't skip) as well as need to write the return statement whereas for Unit we can skip both. This is another reason to avoid using Void in Kotlin code.
Conclusion
So, Unit and Nothing are not a mistake by Kotlin designers in my opinion and are not as questionable as null, undefined and void(0) in Javascript. Unit and Nothing make the functional programming a breeze while providing other useful features mentioned. They are common in other functional programming languages too.
That's it!

Void is uninstantiable type. It is a plain Java class and has no special meaning in Kotlin.
Unit type has only one value. Replaced Java void (notice: not Void). More info in Kotlin docs.
Nothing has no instances (just like Void). It represents "a value that never exists". In Kotlin if you throw an error it is a Nothing (see Kotlin docs).

Related

What is exactly null in kotlin and why i can't cause NPE with it?

Look at the following code running in Kotlin REPL:
>>> null.takeIf({1==2})
res4: kotlin.Nothing? = null
Why this don't cause NullPointerException?
You code doesn't cause NullPointerException because takeIf is an extension function.
Extension functions are translated into method receiver, first argument being the object you invoked your function on.
So instead of null.takeIf { false } (simplifying your example), you could wonder why the following function doesn't throw a NullPointerException:
fun <T> takeIf(me: T, predicate: (T) -> Boolean): T? {
...
}
Well, for that we need to look into takeIf() implementation (removing annotations and contract):
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {
return if (predicate(this)) this else null
}
So, in case your predicate is false (as in your example, 1==2), it just short-circuits and returns null.
What if it's true, then? Will we finally get a NullPointer?
Nope:
val nothing: Nothing? = null.takeIf {
true
}
Kotlin design approach for types aims to eliminate NPEs on purpose. Conditions that might trigger one are limited to, as seen on the docs:
An explicit call to throw NullPointerException();
Usage of the !! operator that is described below;
Some data inconsistency with regard to initialization, such as when:
An uninitialized this available in a constructor is passed and used somewhere ("leaking this");
A superclass constructor calls an open member whose implementation in the derived class uses uninitialized state;
Java interoperation:
Attempts to access a member on a null reference of a platform type;
Generic types used for Java interoperation with incorrect nullability, e.g. a piece of Java code might add null into a Kotlin MutableList, meaning that MutableList should be used for working with it;
Other issues caused by external Java code.
The third option is for NPE-lovers: the not-null assertion operator
(!!) converts any value to a non-null type and throws an exception if
the value is null. We can write b!!, and this will return a non-null
value of b (e.g., a String in our example) or throw an NPE if b is
null:
val l = b!!.length
Thus, if you want an NPE, you can have it, but you
have to ask for it explicitly, and it does not appear out of the blue.
So your code is behaving as expected. See the link for more info
https://kotlinlang.org/docs/reference/null-safety.html

How can Kotlin's Set be covariant when contains() takes E?

I was looking into co- and contravariance in several programming languages' collection libraries, and stumbled over Kotlin's Set interface.
It is documented as
interface Set<out E> : Collection<E>
which means it is covariant – only "producing" E objects, following the Kotlin documentation, not consuming them.
And Set<String> becomes a subtype of Set<Any>.
Yet, it has those two methods:
abstract fun contains(element: E): Boolean
abstract fun containsAll(elements: Collection<E>): Boolean
So when I create a class implementing Set<String>, I have to implement (beside others) contains(String). But later someone can use my class as a Set<Any> and call set.contains(5).
I actually tried this:
class StringSet : Set<String> {
override val size = 2
override fun contains(element: String): Boolean {
println("--- StringSet.contains($element)")
return element == "Hallo" || element == "World"
}
override fun containsAll(elements: Collection<String>) : Boolean =
elements.all({it -> contains(it)})
override fun isEmpty() = false
override fun iterator() = listOf("Hallo", "World").iterator()
}
fun main() {
val sset : Set<String> = StringSet()
println(sset.contains("Hallo"))
println(sset.contains("xxx"))
//// compiler error:
// println(set.contains(5))
val aset : Set<Any> = sset
println(aset.contains("Hallo"))
println(aset.contains("xxx"))
// this compiles (and returns false), but the method is not actually called
println(aset.contains(5))
}
(Run online)
So it turns out that Set<String> is not a "real" subtype of Set<Any>, as the set.contains(5) works with the second but not the first.
Actually calling the contains method even works at runtime – just my implementation will never be called, and it just prints false.
Looking into the source code of the interface, it turns out that the two methods are actually declared as
abstract fun contains(element: #UnsafeVariance E): Boolean
abstract fun containsAll(elements: Collection<#UnsafeVariance E>): Boolean
What is going on here?
Is there some special compiler magic for Set?
Why is this not documented anywhere?
Declaration-site covariance in the form of the out modifier misses a useful use case of making sure that an instance passed as an argument is generally sensible to pass here. The contains functions are a good example.
In the particular case of Set.contains, the #UnsafeVariance annotation is used to ensure that the function accepts an instance of E, as passing an element that is not E into contains makes no sense – all proper implementation of Set will always return false. The implementations of Set are not supposed to store the element passed to contains and thus should never return it from any other function with the return type E. So a properly implemented Set won't violate the variance restrictions at runtime.
The #UnsafeVariance annotation actually suppresses the compiler variance conflicts, like using an out-projected type parameter in an in-position.
Its motiviation is best described in this blog post:
#UnsafeVariance annotation
Sometimes we need to suppress declaration-site variance checks in our classes. For example, to make Set.contains typesafe while keeping read-only sets co-variant, we had to do it:
interface Set<out E> : Collection<E> {
fun contains(element: #UnsafeVariance E): Boolean
}
This puts some responsibility on the implementor of contains, because with this check suppressed the actual type of element may be anything at all at runtime, but it’s sometimes necessary to achieve convenient signatures. See more on the type-safety of collections below.
So, we introduced the #UnsafeVariance annotation on types for this purpose. It’s been deliberately made long and stands out to warn agains abusing it.
The rest of the blog post also explicitly mentions that the signature of contains using #UnsafeVariance improves type-safety.
The alternative to introducing #UnsafeVariance was to keep contains accepting Any, but this option lacks the type check on contains calls that would detect erroneous calls with elements that can't be present in the set due to not being instances of E.

Calling any method on Nothing

Although it is not explicitly stated that Nothing is the subtype of all types, this (among others) suggests it:
fun f(x:Float) { }
fun g(x:Char) { }
fun dead(q: Nothing) {
f(q)
g(q)
}
However, this fails with “unresolved reference”:
fun dead(q: Nothing) {
q.not()
}
Is this a bug or a feature?
Notes:
First piece of code compiles (with warnings), second does not
It's possible to use a Nothing typed receiver, for instance calling toString()
This is legal: {b:Boolean -> b.not()}(q)
Upcast too: (q as Boolean).not()
Equivalent question for Scala
Nothing is Nothing for a reason. You can't call any functions on it. Besides not() is only applicable for Boolean so it is not present on Nothing. In fact there are no methods on Nothing:
/**
* Nothing has no instances. You can use Nothing to represent "a value that never exists": for example,
* if a function has the return type of Nothing, it means that it never returns (always throws an exception).
*/
public class Nothing private constructor()
The documentation pretty much explains its existence.
There is one loophole though. What happens if you return Nothing? from a function?
fun dead(): Nothing? {
return null
}
That's right. It can only return null:
#JvmStatic
fun main(args: Array<String>) {
dead() // will be null
}
I wouldn't say that there is a valid use case to do this but it is possible.
An example for Nothing to indicate nothingness in trees:
sealed class Tree<out T>() {
data class Node<out T>(val value: T,
val left: Tree<T> = None,
val right: Tree<T> = None): Tree<T>()
object None: Tree<Nothing>()
}
Here Nothing denotes a leaf node with no children.
The premise itself doesn't make sense. Nothing is a class which can not be instantiated. You'll never have a variable that holds a Nothing instance.
This means that a function that takes Nothing as a parameter can never be invoked, because you can't get a Nothing instance to pass to it. Anything you write inside it is irrelevant, as is a function like this existing in the first place.
Nothing is made to act like a subtype to all types so that certain uses of language features like throw and return work nicely with the type system. In essence, the compiler lets you pass a Nothing in places where some other type is required, because it knows that you'll never actually reach that code (because again, you can't get a Nothing instance), so it doesn't matter what you're passing in.

Calling a class's method as default arg in constructor

I'm constructing a class and then trying to call a member method of that class as a default value for one of the constructor args.
Why isn't this valid Kotlin?
// unresolved reference: defaultText
class MyThing(val text: String = defaultText()) {
fun defaultText() = "hi"
}
It's possible using two separate constructors in both Java and Kotlin, but then I lose the conciseness of default args.
class MyThing {
private val text: String
constructor(text: String) {
this.text = text
}
constructor() {
this.text = defaultText()
}
private fun defaultText(): String {
return "hi"
}
}
The biggest problem of having a constructor's default parameter expression call a member function of the same instance is that the default arguments are evaluated before the constructor is called.
Given that, such a member function would have to run on a completely un-initialized instance of the class (because even the super constructors will work after that, see this answer about the execution order).
Usually, member functions perform some logic taking the instance state into account, and having a member function run on an empty instance might break some of that logic (e.g. all fields will hold nulls, even the backing fields of Kotlin not-null properties). Overall, even when such calls do not fail at runtime, they are likely introduce subtle bugs, so using a completely uninitialized instance is prohibited.
With regard to the secondary constructor, well, at least it runs after the super constructor initializes some part of the instance, which is thus not completely empty, but it's up to you to make sure you don't use the parts of the class that are not initialized (if you do, you may again encounter a runtime failure or introduce a bug).
I'd rather suggest using a function of a companion object (those are initialized before the class is first used) for this purpose:
class MyThing(val text: String = defaultText()) {
companion object {
fun defaultText() = "hi"
}
}
Or even a top-level function:
fun defaultText() = "hi"
class MyThing(val text: String = defaultText())

Difference between function receiver and extension function

I was reading about Kotlin and did not quite get the idea
from What I understood extension function gives ability to a class with new functionality without having to inherit from the class
and what is receiver the same except it can be assigned to variable
Is there anything else about it?
Can someone give some examples on it
Extension functions:
Like Swift and C#, Kotlin provides the ability to extend a class with new functionality without having to modify the class or inherit from the class.
You might wonder why? Because we cannot edit and add functions to the language or SDK classes. So we end up creating Util classes in Java. I believe all the projects have a bunch of *Utils classes to put the helper methods that are used at multiple places in the code base. Extensions functions help to fix this Util problem.
How do we write a helper method in Java to find whether the given long value refers to today?
public class DateUtils {
public static boolean isToday(long when) {
// logic ...
}
}
And we call that method by passing the long value as an argument:
void someFunc(long when) {
boolean isToday = DateUtils.isToday(when);
}
In Kotlin, we can extend the Long class to include the isToday() function in it. And we can call the isToday() function on the Long value itself like any other member functions in the class.
// Extension function
fun Long.isToday(): Boolean {
// logic ...
}
fun someFunc(time: Long) {
val isToday = time.isToday()
}
Compared to the Util methods, Kotlin provides a much richer syntax using the Extension functions.
This improves the readability of the code which in turns improves its maintainability. And we get a little help from the code completion of the IDE. So we don't have to remember which Util class to use for the desired function.
Under the hood, Kotlin compiler generates the static helper methods as though we had written them as Java static Util methods. So we get this nice and richer syntax in Kotlin without sacrificing any performance.
Similar to functions, Kotlin also supports extension properties where we can add a property to an existing class.
Higher order functions:
A higher-order function is a function that takes functions as parameters, or returns a function.
Lets look at how a higher order function is written.
fun execute(x: Int, y: Int, op: (Int, Int) -> Int): Int {
return op(x, y)
}
Here the third parameter ( op ) is a function and so it makes this function a higher order function. The type of the parameter op is a function that takes 2 Ints as parameter and returns a Int.
To invoke this Higher order function, we can pass a function or a lambda expression:
execute(5, 5) { a, b -> a + b }
Receiver (or Function literal with Receiver or Lambda with Recevier):
A Higher order function that takes an extension function as its parameter is called Lambda with Receiver.
Let's look at the implementation of the apply function which is available in the Kotlin standard library.
inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
The function we pass to this apply function is actually an extension function to the type T. So in the lambda function, we can access the properties and the functions of the type T as though we are writing this function inside class T itself.
Here the generic type T is the receiver and we are passing a lambda function, hence the name Lambda with Receiver.
Another Example:
inline fun SQLiteDatabase.inTransaction(func: SQLiteDatabase.() -> Unit) {
beginTransaction()
try {
func()
setTransactionSuccessful()
} finally {
endTransaction()
}
}
Here, the inTransaction() is an Extension function to the SQLiteDatabase class and the parameter of the inTransaction() function is also an extension function to the SQLiteDatabase class. Here SQLiteDatabase is the receiver, for the lambda that is passed as the argument.
To invoke that function:
db.inTransaction {
delete( ... )
}
Here the delete() is the function of the SQLiteDatabase class and since the lambda we pass is an Extension function to the receiver SQLiteDatabase we can access the delete function without any additional qualifiers with it, as though we are calling the function from inside the SQLiteDatabase class itself.
While #Bob's answer is far more informative on Kotlin than could I hope to be, including extension functions, it doesn't directly refer to the comparison between "function literals with receiver" as described in https://kotlinlang.org/docs/reference/lambdas.html#function-literals-with-receiver and extension functions (https://kotlinlang.org/docs/reference/extensions.html). I.e. the difference between:
val isEven: Int.() -> Boolean = { this % 2 == 0 }
and
fun Int.isEven(): Boolean = this % 2 == 0
The receiver part of the name refers to both of these syntaxes receiving the base Int argument as this.
As I understand it, the difference between the two is simply between one being an expression confirming to a function type and the other a declaration. Functionally they are equivalent and can both be called as:
when { myNumber.isEven() -> doSomething(myNumber) }
but one is intended for use in extension libraries, while the other is typically intended for use as an argument for a function with a function-type parameter, particularly the Kotlin builder DSLs.