To work with a Java API, I need to create a method...
# announcements
e
To work with a Java API, I need to create a method whose return type is
Void
and has the following behavior:
Copy code
override fun getResult(): Void {
        if (!success) throw RuntimeException()
    }
This doesn't compile, because a function with a block body requires a return statement.
How can I fix this code?
r
You probably actually want to return
Void?
(remember Java doesn't have null safety).
Copy code
override fun getResult(): Void? {
    if (success) return null
    else throw RuntimeException()
}
j
Copy code
override fun getResult(): Unit {
        if (!success) throw RuntimeException()
    }
do you need to return Void explicitly?
k
Doesn't Java also require a return statement?
j
that is kotlin
e
I believe so, because I'm extending
Task<Void>
, which requires implementing
getResult(): Void
.
This compiles, but it's not exactly what I want:
Copy code
override fun getResult(): Void {
        throw RuntimeException()
    }
r
@Ellen Spertus Did my code not do what you expected?
e
Sorry, @Ruckus, your code scrolled off my screen, and I missed it at first.
r
Basically, you can't actually return a
Void
value, just like you can't return a
Nothing
value in Kotlin (there is no instance of
Void
). In order to get this to work, you either need to diverge (not return like your always fail example) or change your return type (you can use
Void?
to fit better into the Java world, or if it makes more sense you can change to extend
Task<Unit>
and use @James's code.
c
In Java,
Void
has a private constructor, so it is impossible to actually get an instance of
Void
. Any method contract that requires you to return
Void
is implicitly requesting you return
null
instead. I think having your Kotlin method have a return type of
Void?
and returning null on the
success
branch is the way to go.
âž• 2
e
Yes, @Ruckus, your solution works. I didn't think I'd be able to change the return type. Thank you very much!
đź‘Ť 1
r
Yeah, Kotlin has to make some assumptions when overriding Java, so if there's no annotations it chooses the "safest" by default (arguments are nullable and return types aren't), but they're actually platform types so you can choose your nullability as you see fit.
🙏 1
s
I’m with James, I assume Kotlin’s Unit to be mapped to Java’s void. So
Copy code
override fun getResult(): Unit {
    if (!success) throw RuntimeException()
}
should work and is more idiomatic than Void?. This playground code overrides Java’s Object’s finalize method which returns void in Java by using Unit and it works fine:
Copy code
class KotlinObject() : java.lang.Object() {
    override fun finalize(): Unit {}
}
https://pl.kotl.in/n_umKF6c8
k
But none of that works if Java code is forcing you to implement
Task<Void>
.
s
It’s interesting that the interop doesn’t automatically translate
Task<Unit>
but it does
Task<Void?>
, because technically
Void?
is as far from
Void
as is
Unit
. (What about ’Nothing?
which is the same set as 'Void?
??) I guess that the instance of
Task<Void?>
is passed back to Java code? Because otherwise using Task<Unit> is probably the answer. Something similar happens when I want to use the
ExecutorService
, which only handles `Callable`s and not `Runable`s. In that case
Callable<Unit>
is the way to go.
r
technically
Void?
is as far from
Void
as is
Unit
What? How on Earth did you come to that conclusion?
Void
has nothing to do with
Unit
.
c
The difference is that
Task<Unit>
must return something, namely
Unit.INSTANCE
.
Task<Void>
does not make sense, since you cannot get a non-null instance of
Void
to return, and thus
Task<Void?>
must return null
Unit
is analogous to
void
in the sense that it is the default return type, but it is not the same thing as
void
.
void
has no instance,
unit
has an instance and is non-null, and has a different meaning from
void
in Kotlin’s null-safe world