Chapter 63. Optional Is a Lawbreaking Monad but a Good Type
Nicolai Parlog
In most programming languages, empty-or-not-empty types are well-behaved monads. (Yes, I used the M-word—don’t worry, no math.) This means their mechanics fulfill a couple of definitions and follow a number of laws that guarantee safe (de)composition of computations.
Optional’s methods fulfill these definitions but break the laws. Not without consequences...
Monad Definition
You need three things to define a monad—in Optional’s terms:
-
The type
Optional<T>itself -
The method
ofNullable(T)that wraps a valueTinto anOptional<T> -
The method
flatMap(Function<T, Optional<U>>) that applies the given function to the value that is wrapped by theOptionalon which it is called
There’s an alternative definition using map instead of flatMap, but it’s too long to fit here.
Monad Laws
Now it gets interesting—a monad has to fulfill three laws to be one of the cool kids. In Optional’s terms:
-
For a
Function<T, Optional<U>> fand a valuev,f.apply(v)must equalOptional.ofNullable(v).flatMap(f). This left identity guarantees it doesn’t matter whether you apply a function directly or letOptionaldo it. -
Calling
flatMap(Optional::ofNullable)returns anOptionalthat equals the one you called it on. This right identity guarantees applying no-ops doesn’t change anything. -
For an
Optional<T> oand two functions ...