I'm late to the party here (and everyone is glowingly praising `Option`) but I'd like to point out that `Option` **comes with significant downsides** for maintainability.
This is a re-hash of Clojure author Rich Hickey's discussion of maybe types here: https://www.youtube.com/watch?v=YR5WdGrpoug
While not as bad a untyped null references,
## Option types are a 500 million dollar mistake
### Starting at the beginning
There are 3 ways of handling nullability:
**First:** the billion dollar mistake. A reference can be null but this fact is not encoded in the type system.
This is what Java does. Anytime you receive a pointer to something you don't know whether or not it is pointing to an actual object or null.
```java
string foo(String x) {
// this might work or it might throw a null pointer exception
return x.substring(0, 1);
}
// both of these invocations are allowed by the compiler
// however one will fail at runtime.
foo(null);
foo("xyz");
```
**Second:** Null references exist but the type system understands that fact and forces the programmer to specify when null is expected and when it is not expected.
This is how TypeScript handles null.
```javascript
function foo(x: string): string {
return x.substr(0, 2);
}
foo(null); // You cannot write this in TypeScript as x was not declared as being nullable.
foo("sdf"); // works fine
function relaxedFoo(x?: string): string {
if (x != null) // compiler forces you to check for null
return x.substr(0, 1);
return '';
}
relaxedFoo(null); // works fine. We indicated to the compiler that relaxedFoo can handle null references
```
**Third**:
The `Option`/ `Maybe` type. This "removes" null altogether. The easiest way to think about this is that rather than having a thing that is null or not null, now you have a collection that is empty or not empty. `Option` has already been discussed at great length in the other answers here.
## `Option` -- the 500 million dollar mistake
So what is so bad about `Option` that I'd spend an hour on Sunday morning writing about it?
It has to do with program maintenance.
### Relaxing Requirements
Take a look at the following code:
```
function foo(x: string): string {...}
```
`foo` requires all callers to always pass a string. But what if tomorrow I want to relax that constraint? Callers can call me with a string or without.
If I used `Option` I'd end up here:
```
function foo(x: Option<string>): string {...}
```
which breaks all callers as `Option<string>` in not compatible with `string`.
Callers doing `foo('sdf');` must be updated to `foo(Option('sdf'));`. Pretty problematic if this is a library released publicly.
However, this isn't an issue in TypeScript and other languages that understand null references. In those languages I would do:
```
function foo(x: ?string): string {...}
```
`?string` is a union type of `string` and `null`, thus no existing callers break. I can release an update to my library and not break any of its consumers.
```
foo('sdf'); // requires no change as 'sdf' is allowed in the type union of `null | string`
```
The same problem with `Option` also exists in the reverse -- when making return types provide stronger guarantees.
I.e.,
Changing `foo(): Option<string>` to `foo(): string` shouldn't be considered a breaking change.
Of course `foo(): string` to `foo(): Option<string>` is breaking (and should be breaking) since a new type is added.