In praise of Vavr’s Option

von David Schmitz | 27. Mai 2017 | Allgemein, English, Software Engineering

David Schmitz

CTO

Null is sometimes considered the billion dollar mistake. One could argue about this forever, but certainly, null has lead to a lot of awful code.

Most functional programming languages offer a concept called Option or Maybe to deal with the presence or absence of a value, thus avoiding null. Wikipedia defines the Option type as follows:

In programming languages (more so functional programming languages) and type theory, an option type or maybe type is a polymorphic type that represents encapsulation of an optional value; e.g., it is used as the return type of functions which may or may not return a meaningful value when they are applied.

This short post gives praise to the Vavr version of Option. We show how to use it and show its advantages over JDK8 Optional.

Vavr – Elevator pitch

Vavr, previously known as Javaslang, is a lightweight library that brings Scala-like features to Java 8 projects. It focuses on providing a great developer experience both through consistent APIs and extensive documentation.

Vavr offers many abstractions such as functional data structures, value types like Lazy and Either and structural decomposition (a.k.a. pattern matching on objects). Here we’ll only highlight the Vavr Option.

If you have ever yearned for really good immutable and persistent collections, working value types, but could not move to Scala and friends because you are working on a brownfield project…then Vavr might just be your fix.

Optional FTW

Java 8 introduced Optional to handle the absence or presence of a value. Without Optional, when you face a method like this

public User findUser(String id) {
  ...
}

you need to rely on Javadoc or annotations like @NotNull to decipher if that method returns a null.

Using Optional things can be stated quite explicitly:

public Optional<User> findUser(String id) {
  ...
}

This literally says “sometimes no User is returned”. null-safe. Say “adios” to NullPointerExceptions.

However…

As with all of Java 8’s functional interfaces, Optionals API is rather spartanic, just a dozen methods, with “highlights” such as

Optional.ofNullable(user)

If you are used to the expressivness of Scala’s Option, then you will find Optional rather disappointing.

Furthermore, Optional is not serializable and should neither be used as an argument type nor stored as a field – at least according to the design goals of the JDK experts (http://mail.openjdk.java.net/pipermail/jdk8-dev/2013-September/003274.html).

Vavr Option to the rescue

The Vavr Option takes a different approach. See the following image, that illustrates the type hierarchy.

Option follows the design of other functional programming languages, representing absence and presence by distinct classes, None and Some respectively. Thus avoiding the ofNullable nonsense.

Option.of(user)

And the result would either be a Some<User> or a None<User>.

Internally absence is represented as null, so you if you wanted to wrap a null, you need to use

Option.some(null)

although I do not recommend this approach. Just try the following snippet and you will see what I mean

Option.<String>some(null)
      .map(String::toUpperCase);

Option is tightly integrated with Vavr’s Value and Iterable types. This allows for a very consistent API. You can basically treat an Option like a collection with zero or one elements.

This might sound like a small thing, but consider this JDK8 Optional example.
We have a list of users.

List<User> users = new ArrayList<>(...);

And now an Optional<User> which we want to add to the list.

Optional<User> optionalUser = Optional.ofNullable(user);
optionalUser.map(users::add);

The intention is lost in the baroque syntax enforced by JDK8 Collection and Optional API.

Vavr’s Option allows for a much cleaner syntax (note that we are using io.vavr.collection.List<T> not java.util.List<T>).

List<User> users = List.of(...);
Option<User> optionUser = Option.of(user);
List<User> moreUsers = users.appendAll(optionUser);

Vavr treats Some<T> as a collection with one element, and None<T> as an empty collection, leading to cleaner code. In addition, note that a new list is created, because Vavr collections are immutable and persistent – a topic for a different day.

Option has more syntactic sugar for us:

Option<String> driverName = Option.when(age > 18, this::loadDrivingPermit)
                                  // Option<DrivingPermit>
                                  .peek(System.out::println)
                                  // Print it to the console
                                  .map(DrivingPermit::getDriverName)
                                  // Fetch the driver's name
                                  .peek(System.out::println);
                                  // Print it to the console

Of course, as I said, this is basically sugar, but anything that reduced boilerplate code is highly appreciated.

Option is thightly integrated into Vavr’s overall API and architecture. You can easily combine it with Vavr’s Try monad, that helps dealing with exceptions in a functional way. Take the following example.

Option<Configuration> config = Try.of(Configuration::load)
                                  .toOption();

We Try to load a Configuration and convert the result to Option. If an exception is thrown, then the
result is None otherwise it is Some.

Finally, you can use Vavr’s pattern matching to decompose an Option

Match(option).of(
   Case($Some($()), String::toUpperCase),
   Case($None(),    () -> ""));

If you have ever coded in a functional programming language, then this should be familiar to you. We basically Match the option against two patterns $Some($()) and $None(). Depending on the matched pattern we either convert the string to uppercase or return an empty string.

Using Vavr Jackson you can even use Option and all other Vavr datatypes over the wire. For Spring Boot projects you only need to declare the module such as:

@Bean
public Module vavrModule() {
    return new VavrModule();
}

Summary

I hope this short post illustrates the usefulness of Vavr and its Option abstraction.

Vavr as a library offers many amazing extensions for object-functional programming in Java, even for brownfield projects. You can leverage its utilities where they make sense and need not migrate to Scala or similar platforms to reap at least some benefits of functional programming.

Of course, this is all syntactic sugar. But as any good library, Vavr fixes things, the core JDK cannot take care of so easily without breaking a lot of code.

Future posts will cover its other amazing features like pattern matching, property based testing, collections and other functional enhancements.