Should Java have a unit type?
James Roper
james at lightbend.com
Thu May 10 01:40:10 UTC 2018
Hi all,
I'm interested in opinions on whether Java should have a unit type. I
apologise if this has already been discussed on this list before, I did
search for it but didn't find anything.
By unit type, I'm referring to a type that represents no value. When a
Java method returns no value, void is used, however, void is not a type.
java.lang.Void exists as a placeholder class for use in reflection, but it
doesn't seem that it's meant to be used directly as a type.
In spite of this, java.lang.Void is used in some places in the JDK as a
type, for example, it's used by CompletionStage in methods such as
thenAccept to represent an operation that can complete or fail in future
but has no value:
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletionStage.html#thenAccept-java.util.function.Consumer-
Working with it in this way is a little clunky and counter intuitive, Void
is uninstantiable, so how can a CompletionStage<Void> ever be redeemed? The
answer is, it gets redeemed with null. Are null and void the same thing?
Apparently, according to this API, but they aren't really, null represents
the absence of a value that could exist, and is treated as such in APIs
like java.util.Optional, which is a different thing from no value.
Now perhaps the use of Void in this way by CompletionStage means the horse
has already bolted, and that now Void is a unit type with a singleton
instance represented by null, by default.
But in my opinion, it really isn't ideal. One issue is that it means any
API that uses Void types won't play well with other APIs that don't accept
nulls - a consequence of void and null being different things. A big one in
this case is Reactive Streams, onNext does not accept null, so if you
asynchronously map a reactive stream, and the asynchronous operation you do
returns CompletionStage<Void> (this is actually a common thing to do, eg,
if you're doing a sequence of operations, and the last one is a commit, it
is becoming common practice for asynchronous commit methods to return
CompletionStage<Void>), then you need to thenApply that CompletionStage to
some other non null unit type before you can emit it to the stream.
So it's my opinion that Java should have a unit type. This could be done by
promoting Void to a unit type, not just a placeholder type, and giving it a
singleton instance. That approach would mean existing uses of Void as a
unit type would be source compatible, and can migrate to using the instance
instead of null.
Another approach would be to introduce a new type, perhaps java.lang.Unit.
Both Scala and Kotlin have their own unit types, scala.Unit and kotlin.Unit
respectively. Akka did something a little more interesting, it has two unit
types, used to indicate two different intents, the first is NotUsed, which
is used to indicate that a type parameter has no significant meaning, and
the second is Done, which is used to indicate that a type parameter of this
type indicates that whatever it represents has been completed successfully
- this type is typically used in combination with CompletionStage, while
NotUsed might be used in place of Void in PrivelegedAction, as described
here:
https://docs.oracle.com/javase/8/docs/technotes/guides/security/doprivileged.html
Regards,
James
--
*James Roper*
*Senior Octonaut*
Lightbend <https://www.lightbend.com/> – Build reactive apps!
Twitter: @jroper <https://twitter.com/jroper>
More information about the core-libs-dev
mailing list