Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I have to return Unit.INSTANCE when implementing in Java a Kotlin function that returns a Unit?

If I have a Kotlin function

fun f(cb: (Int) -> Unit) 

and I want to call f from Java, I have to do it like:

f(i -> {      dosomething();      return Unit.INSTANCE; }); 

which looks very ugly. Why can't I just write it like f(i -> dosomething());, since Unit in Kotlin is equivalent to void in Java?

like image 243
Randy Sugianto 'Yuku' Avatar asked Jun 15 '16 07:06

Randy Sugianto 'Yuku'


People also ask

What is unit return 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.

Does Kotlin need return?

The return keyword already is optional for functions* in Kotlin.

What is the return type in Kotlin when function returns nothing useful?

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.

How do I return a function in Kotlin?

To return values, we use the return keyword. In the example, we have two square functions. When a funcion has a body enclosed by curly brackets, it returns a value using the return keyword. The return keyword is not used for functions with expression bodies.


Video Answer


1 Answers

Unit in Kotlin is mostly equivalent to void in Java, however only when the rules of the JVM allow it.

Functional types in Kotlin are represented by interfaces like:

public interface Function1<in P1, out R> : Function<R> {     /** Invokes the function with the specified argument. */     public operator fun invoke(p1: P1): R } 

When you declare (Int) -> Unit, from Java's point of view this is equivalent to Function<Integer, Unit>. That's why you have to return a value. To work around this problem, in Java there are two separate interfaces Consumer<T> and Function<T, R> for when you don't have/have a return value.

The Kotlin designers decided to forgo the duplication of functional interfaces and instead rely on compiler "magic". If you declare a lambda in Kotlin, you don't have to return a value because the compiler will insert one for you.

To make your life a little bit easier, you can write a helper method that wraps a Consumer<T> in a Function1<T, Unit>:

public class FunctionalUtils {     public static <T> Function1<T, Unit> fromConsumer(Consumer<T> callable) {         return t -> {             callable.accept(t);             return Unit.INSTANCE;         };     } } 

Usage:

f(fromConsumer(integer -> doSomething())); 

Fun fact: The special handling of Unit by the Kotlin compiler is the reason you can write code like:

fun foo() {     return Unit } 

or

fun bar() = println("Hello World") 

Both methods have return type void in the generated bytecode but the compiler is smart enough to figure that out and allow you to use return statements/expressions anyway.

like image 135
Kirill Rakhman Avatar answered Oct 19 '22 12:10

Kirill Rakhman