# Optional Is a Law-breaking Monad but a Good Type

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 value`T`

into an`Optional<T>`

. - The method
`flatMap(Function<T, Optional<U>)`

that applies the given function to the value that is wrapped by the`Optional`

on 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>> f`

and a value`v`

,`f.apply(v)`

must equal`Optional.ofNullable(v).flatMap(f)`

. This*left identity*guarantees it doesn't matter whether you apply a function directly or let`Optional`

do it. - Calling
`flatMap(Optional::ofNullable)`

returns an`Optional`

that equals the one you called it on. This*right identity*guarantees applying no-ops doesn't change anything. - For an
`Optional<T> o`

and two functions`Function<T, Optional<U>> f`

and`Function<U, Optional<V>> g`

the results of`o.flatMap(f).flatMap(g)`

and`o.flatMap(v -> f.apply(v).flatMap(g))`

must be equal. This*associativity*guarantees that it doesn't matter whether functions are flat-mapped individually or as a composition.

While `Optional`

holds up in most cases, it doesn't for a specific edge case. Have a look at `flatMap`

's implementation:

`public <U> Optional<U> flatMap(Function<T, Optional<U>> f) {`

if (!isPresent()) {

return empty();

} else {

return f.apply(this.value);

}

}

You can see that it doesn’t apply the function to an empty `Optional`

, which makes it easy to break left identity:

`Function<Integer, Optional<String>> f =`

i -> Optional.of(i == null ? "NaN" : i.toString());

*// the following are not equal*

Optional<String> containsNaN = f.apply(null);

Optional<String> isEmpty = Optional.ofNullable(null).flatMap(f);

That’s not great, but it’s even worse for `map`

. Here, associativity means that given an `Optional<T> o`

and two functions `Function<T, U> f`

and `Function<U, V> g`

the results of `o.map(f).map(g)`

and `o.map(f.andThen(g))`

must equal.

`Function<Integer, Integer> f= i -> i == 0 ? null : i`

Function<Integer, String> g = i -> i == null ? "NaN" : i.toString();

*// the following are not equal*

Optional<String> containsNaN = Optional.of(0).map(f.andThen(g));

Optional<String> isEmpty = Optional.of(0).map(f).map(g);

# So what?

The examples may seem contrived and the importance of the laws unclear, but the impact is real: In an `Optional`

chain you can't mechanically merge and split operations because that may change the code's behavior. That is unfortunate because proper monads let you ignore them when you want to focus on readability or domain logic.

But why is `Optional`

a broken monad? **Because ****null****-safety is more important!** To uphold the laws, an `Optional`

would have to be able to contain `null`

while being non-empty. And it would have to pass it to functions given to `map`

and `flatMap`

. Imagine, everything you did in `map`

and `flatMap`

had to check for `null`

! *That* `Optional`

would be a great monad, but provide zero `null`

-safety.

No, I'm happy we got the `Optional`

that we got.