By Rich Hickey, creator of Clojure. From Nov 2018.
Notes
When do we use nulls?
- When we optionally require something. We can avoid this in Clojure because we can have variadic functions/keyword args.
- In returns - eg, map lookup.
- Managing partial information. In Clojure we don’t use null for this.
We can deal with these using Maybe (Haskell) or Option (Scala).
The cost of Maybe
The costs of Maybe is in program maintenance.
If we go from foo :: x -> y
to foo :: Maybe x -> y
, this is enforced by the compiler, which is good, but this breaks existing callers, which is bad.
This is an easing of requirements, so it should be a compatible change.
If we go from foo :: x -> Maybe y
to foo :: x -> y
we also break existing callers.
This time we’re strengthening a guarantee, which should also be a compatible change.
Maybe/Either are not ‘or/union’ in the type system. They show the lack of first class union types.
Other type systems work differently - eg, Kotlin’s nullable types (and the above changes from Nullable
to NonNull
in Kotlin wouldn’t break code).
Also Union Types in Dotty.
What about Clojure
Clojure is dynamically typed so we don’t run into this problem, until we use spec.
Partial information
Aggregation is about information that travels together.
We can model this as Sets or Slots - the former is a map, the latter is a record (or class in non Clojure). Maps are the simplest functions in programming. Records are PLOP - Place oriented programming - they are not functions.
With a Record, each place must be something in the place (even if it’s null
).
But with Maps, they are too open, until you add spec.
What do we do when something is allowed to be missing? You leave the key out (instead of having a Maybe/Nullable).
Part of the problem of Maybes in aggregates is that they don’t tell you when the field will be missing or required.
I stopped about half way through when he started going into spec since I’m not that into Clojure at the moment.