An Optional’s place in Kotlin

With nullability being a first-class citizen in Kotlin’s type system, is there any need for an Optional type?

With nullability being a first-class citizen in Kotlin’s type system, the need for an Optional type seems all but diminished. Just because you can explicitly express nullability, however, does not mean that null is always allowed.

For example, Retrofit provides adapters for RxJava 1.x and 2.x which allow modeling your requests as a single-element stream.

interface MyApiService {
  fun userSettings(): Observable<Settings>

RxJava 2 differs from RxJava 1 in that it does not allow null in its streams. If we’re using RxJava 2 and the converter for Settings returns null an exception will occur. Thus, in order to represent the absence of a value for the response body inside this stream we need an abstraction like Optional.

Retrofit 2.3.0 introduces two new delegating converters for the Optional types in Guava and Java 8. Unlike the other converters for libraries like Moshi, Gson, and Wire, these new ones are different in that they don’t actually convert bytes to objects. Instead, they delegate to other converters for processing the bytes and then wrap the potentially-nullable result into an Optional.

val retrofit = Retrofit.Builder()

With one of the Optional converters added alongside a serialization converter, requests whose bodies may deserialize to null can be changed to instead return an Optional.

interface MyApiService {
  fun userSettings(): Observable<**Optional<**Settings**>**>

Today’s Retrofit 2.3.0 release contains the same JSR 305 annotations for explicit nullability in Java and Kotlin as our recent Okio and OkHttp releases. As we’ve seen above, though, just having these annotations​ or a type system that can model nullability sometimes is not enough. For these cases, in Java and Kotlin alike, the use of Optional has its place.

This post is part of Square’s “Square Open Source ♥s Kotlin” series.

View More Articles ›