Java interop: Unit closures required to return kotlin.Unit

Given this function:

object Tmp {
    @JvmStatic fun hello(f: () -> Unit) {
    }
}

The following Java code doesn’t compile

public class Hello {
    public void asd() {
        Tmp.hello(() -> {
        });
    }
}

as it requires the closure to return Unit.INSTANCE.
Suggestion: Add @JvmVoid annotation to denote Units that should actually behave as void

10 Likes

I don’t understand why Unit is better than void or Void…

Someone can help me?

Unit is a type (unlike void) and has a value (unlike Void). This enable uniform treatment of Unit when it comes to generic classes. I.e. we don’t need another two types: a function that returns something and a function that returns void. It’s all one type: a function that returns something tat may be Unit.

Introducing void would pose many problems in areas like type inference, compositionality of any sort of functions, etc

1 Like

@abreslav Could you explain in which case it’s better to use Nothing over Unit ?

Thanks for response,
those are good points.
I’m interested to know how you will fix this issue.

Nothing is for a function/method that never returns,
i.e. System.exit() should return Nothing.

Also “throw” statement returns nothing.

All statements after a Nothing one are unreachable.

I’m not suggesting introducing void as a kotlin type, but rather annotating Unit for better Java interop. There is a straightforward translation from void to Unit which the compiler could do:

If void is covariant:

fun f(): @JvmVoid Unit {..}

would compile to two functions, one for kotlin, one for java:

public void f_kotlin(): Unit {
  ..
}
public void f_java() {
  f_kotlin();
}

And if it’s contravariant the java version would just wrap void functions and pass in Unit.INSTANCE automatically.

4 Likes

This functionality is also required to maintain compatibility with code that inspects the return type of a method and will fail if it is not void. For example, in the Arquillian testing suite, the org.jboss.arquillian.junit.Arquillian.validatePublicVoidNoArgMethods() method checks to make sure that a test function annotated with @BeforeClass returns void. Without some way to generate the correct signature, Kotlin can’t be used with these libraries.

Hello, is there any solution so far to pass () -> {} in Java to Kotlin function as an argument, which is declared as () -> Unit?

5 Likes

Any updates on this? Learning Kotlin second day and facing this already. The best I come up with is
Kotlin:

fun created(callback: (s: Subscriber) -> Unit)  {
    callback(this)
}

Java (ugly return null):

subscriber.created(s -> {
    System.out.println("User " + s + " was created");
    return null;
});

Any better solution for this?

Better no.
Advise which is not like by kotlin itself:
If you want to be java-compatible, declare your lambdas using java-functional interfaces.
Kotlin has fun interfaces themselves, but I didn’t look into them yet

for everyone stumbling over this problem, i use following workaround.

My kotlin function is this:

fun justSomeTest(f:()->Unit){}

To call it in Java, it would look like this:

bla.justSomeTest(()->{return null;});

But with adding an overload in kotlin with the Java Interfaces like this:

fun justSomeTest(f:Runnable)=justSomeTest { f.run() }

the java code becomes the following:

bla.justSomeTest(()->{});

Obviously this also works with the Java interfaces Function, Consumer, Supplier etc the same way