Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the difference between () -> Unit and (Unit) -> Unit types?

Tags:

kotlin

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?

like image 587
netimen Avatar asked Feb 12 '16 10:02

netimen


People also ask

What does () -> unit mean in Kotlin?

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.

What is meant by unit type?

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.

What is unit in computer programming?

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.


1 Answers

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


In your example, type inference happens as follows:
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
  1. map: (T) -> U = { }, thus a replacement for U is Unit returned from { }.
  2. Therefore call should be (Unit) -> Unit.
  3. call: () -> Unit which is not the same to (Unit) -> Unit, as stated above. Error.
like image 130
hotkey Avatar answered Oct 13 '22 21:10

hotkey