Java and Optional


#1

Are there any plans to add nullable sugar to java.util.Optional? I’m not saying that generated APIs should use them where previously there were nullable return types, but being able to treat Optional values as nullable from other APIs or, when implementing interfaces from those APIs, return a nullable value where an Optional is expected, would be really really really nice.


#2

I don’t think kotlin would benefit from any syntactic sugar for optionals. It would just lead to people using them even though they are inferior to nullables in any regard.
If you have to interface with java code using optionals often you could just create 2 little utility functions

fun <T: Any> T?.asOptional() = Optional<T>.ofNullable(this)
fun <T: Any> Optional<T>.asNullable: T? = this.orElse(null)

#3

I have those already, but it would be nice to not need to use them at all. And I don’t think it would lead to people using them over nullable types - I’m talking just about compatibility. The same way Kotlin has SAM conversions, but not if the interface was defined in Kotlin.


#4

For compatibility you can also annotate your Java code with nullability annotations.


#5

The special language feature for that is absolutely unnecessary. If you are using kotlin, than optional are needless and you are better to remove them from code and replace by nullables. If you are interacting with java code, then functions (I use properties) like the ones shown by @Wasabi375 are quite sufficient.


#6

I could, but this isn’t my Java code, it’s someone else’s.


#7

They might be ‘sufficient’ but Kotlin’s about seamless interfacing with sugar where necessary. For example how MutableList and List are both java.util.List but behave differently.


#8

If you are using Intellij, you can annotate third-party API with external annotations.


#9

Is there a way to distribute that annotated API as part of my library?


#10

I have created a issue on YouTrack asking for this feature. However, there has not been any progress for almost a year now.


#11

Because maximum that could be done is the standard library support for conversion methods or properties. No language changes will be ever done for the feature that requires two additional lines of code for the whole program.


#12

It’s not just a matter of two additional conversion functions — it’s also calling them throughout the code base in places where such conversion is required, which definitely adds some boilerplate.

However making such conversion implicit is not in the spirit of Kotlin, since it avoids having implicit conversions in general.


#13

Maybe there can be an argument for adding an annotation to functions so that the compiler automatically creates overloads with Optionals

@CreateOptionals
fun foo(bar: Int?) {}
// auto generates
fun foo(bar: Optional<Int>) = foo(bar.orElse(null)

However I am not sure how this would work with functions returning a nullable value, because you can’t overload just based on the return type. But I guess there might be some tricks that can be done by renaming the generated function visible to the jvm.
That way at least it would be possible to solve the problem of implementing interfaces using Optionals.


#14

This is the exact opposite of what I’m asking for. I’m not asking for Optionals to be generated for public interfaces, I’m asking for Optionals to be interpreted from Java interfaces as nullables.


#15

What about nullable optionals? I don’t think anyone will actually use it, but it could be done. What about lists of optionals?


#16

An Optional<T>? would just be treated as T?. Null would be the same thing as Optional.empty(). And you can have lists of nullable types, can you not?


#17

I think the following could be a way of reasoning for those who made the decsion to not support Optional directly with nullable Kotlin types.

  1. Automatic Kotlin nullable type T? conversion to Optional<T>
    All Kotlin methods from Java perspective have appropriate Nullable and NotNull annotations for parameters and return types. Adding more methods with Optional is not required and just blows up the generated code (which would be really bad for Android DEX files). Possibly, this could even create platform declaration clashes because of generics type-erasure. The latter would restrict Kotlin heavily.
    Returning Optional instead would simply suggest that Kotlin language devs think, that Optional solves the problem of NPEs for Java (which it does not. See below if you want to know why). Optional does not solve the same problem inside the Java language as Kotlin’s nullable type does inside of the Kotlin language.

  2. Automatic Java Optional<T> conversion to T?
    It is arguable that this could be useful in terms of readability.
    But still, Optional does not solve the NPE problem in Java.
    Kotlin does not say "Using, Optional<T> is fine, it solves the same problems as Kotlins T?" because it does not.
    I understand Kotlin to be like “Well, if you insist on using Optional<T>, you can do so, and Kotlin is compatible with that, you can write same (complicated) code using optionals in Kotlin if you insist. But we prefer @Nullable and @Notnull annotations.”

Why Optional does not solve NPE problem?
If Optional was used strictly by a programmer (for example by using a tool that ensures he never passes nullable values into normal variables, functions, and so on), he would be able to solve the NPE problem using Optionals.
But then, he would be unable to use the Java standard lib, because many methods return or take nullable types.
One example is java.util.Map#get. It returns a value of type V, not an Optional<V>, but it can return null if the key was not found.
So if the programmer would want to use Optional to solve NPE problems, he could not use the Java standard library, and thus could not write Java anymore and also not it’s libraries.

How does Kotlin do this differently?
Kotlin does not (easily) allow you to use the Java classes that return nullable values directly, but Kotlin replaces those interfaces and classes transparently with type-safe classes.
For example the above Java Map is transparently replaced with Kotlins interface kotlin.collections.Map which states that get returns a V?


#18

Let me make this more clear with an example.

fun opt(x:Optional<String>) {}
fun opt(x:Optional<Int>) {}

The above does not compile, because the generated JVM methods have conflicting overlords. It is the same if you write this in Java.

fun opt(x:String?) {}
fun opt(x:Int?) {}

This code instead does compile and the generated JVM methods are fine. And this is simply possible because Kotlin does not translate the parameters to Optionals

So what would happen if we would make Kotlin translate T? in function parameters to Optional<T>? The following illegal (Java equivalent) code would be generated by Kotlin compiler:

public static final void opt(Optional<String> x) {    }
public static final void opt(Optional<Integer> x) {    }

Instead now Kotlin creates valid code which in Java-ways says the same about nullability:

public static final void opt(@Nullable String x) {    }
public static final void opt(@Nullable Integer x) {    }

#19

It does not solve it in a way that can be checked at compile-time. You can always assign null to a Optional variable, and the compiler will allow it. Sure, you can try hard to use it strictly, but that is the point. With Kotlin’s nullable types you don’t need to try it is enforced by the compiler.


#20

@fatjoe79: Yes, that, but Optional is also in fact weaker. Because Optionals are based on generics, and generics are weak. They are not strong enough to enforce their type-parameters all the way through the compiler. Their type is erased during compile-time and thus on JVM bytecode level some methods would have the same signature and would be indistungishable during runtime. This is not allowed by the compiler. The compiler itself has to account for the lost type. And thus using Optionals you can not write the same code as with Kotlin’s nullable types.