I have following functions:
fun <T, U> process(t: T, call: (U) -> Unit, map: (T) -> U) = call(map(t))
fun <T> processEmpty(t: T, call: () -> Unit) = process(t, call, {}) // error
but the processEmpty
is not compiling. The error message is Type mismatch: inferred type is () -> kotlin.Unit but (kotlin.Unit) -> kotlin.Unit was expected
. But if I change this function to
fun <T> processEmpty2(t: T, call: (Unit) -> Unit) = process(t, call, {}) // OK
So what's the difference between () -> Unit
and (Unit) -> Unit
types? Why first version of processEmpty
isn't compiling?
Unit in Kotlin corresponds to the void in Java. Like void, Unit is the return type of any function that does not return any meaningful value, and it is optional to mention the Unit as the return type. But unlike void, Unit is a real class (Singleton) with only one instance.
In the area of mathematical logic and computer science known as type theory, a unit type is a type that allows only one value (and thus can hold no information). The carrier (underlying set) associated with a unit type can be any singleton set.
In procedural programming, a unit could be an entire module, but it is more commonly an individual function or procedure. In object-oriented programming, a unit is often an entire interface, such as a class, or an individual method.
Unit
is actually a type that has exactly one value (the value is Unit
itself; also, this is why it is named Unit
). It corresponds to void
in Java, but it's not the same.
Kotlin compiler treats functions with no declared return value as Unit
-returning functions, and return Unit
can also be omitted. This is why { }
is a Unit-returning function.
But this is not applied to arguments. To be strict, when you declare a function with Unit
argument or (Unit) -> Unit
function variable, you have to pass an argument of type Unit
at call site. The only value to pass is Unit
.
A lambda with no specified arguments like { doSomething() }
is treated both as a function with no arguments and as a function with single implicit argument it
. You can use { }
both as () -> Unit
and (Unit) -> Unit
.
As to the call site, as said above, Unit
has to be passed:
val f: (Unit) -> Unit = { println("Hello") }
f(Unit) // the only valid call
Whereas () -> Unit
functions do not need an argument to be passed:
val f: () -> Unit = { println("Hello") }
f() // valid call
fun <T, U> process(t: T, call: (U) -> Unit, map: (T) -> U) = call(map(t))
fun <T> processEmpty(t: T, call: () -> Unit) = process(t, call, {}) // error
map: (T) -> U = { }
, thus a replacement for U
is Unit
returned from { }
.call
should be (Unit) -> Unit
.call: () -> Unit
which is not the same to (Unit) -> Unit
, as stated above. Error.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With