Type Driven Development: Maybe

Written by

in

Part 17 – Maybe

This is a series of posts I’m writing about using types as another tool in software development, Continuous Delivery, & keeping LLM’s honest. They’re also a design & refactoring tool, a communication tool, and reduce how many tests you have to write.

Parts
  1. Part 1 – Branded Types
  2. Part 2 – Product Types
  3. Part 3 – Union & Discriminated Unions
  4. Part 4 – Non-Empty Collections
  5. Part 5 – Indexed Types
  6. Part 6 – unknown vs any
  7. Part 7 – Result
  8. Part 8 – Schema
  9. Part 9 – Total Function
  10. Part 10 – Errors as Values
  11. Part 11 – Property Tests
  12. Part 12 – Type Proofs
  13. Part 13 – Exhaustiveness Checking
  14. Part 14 – Parse, Don’t Validate
  15. Part 15 – Anti-Corruption Layer
  16. Part 16 – Opaque Types
  17. Part 17 – Maybe
  18. Part 18 – Smart Constructors
  19. Part 19 – Pipeline
  20. Part 20 – Railway Oriented Programming
  21. Part 21 – Typestate
  22. Part 22 – Capabilities
  23. Part 23 – Immutability
  24. Part 24 – Making Impossible States Impossible
  25. Part 25 – Type Driven Development: How to do it
  26. Part 26 – Final Thoughts

Option/Maybe is a type to model data is not there & be a replacement for null/nil/undefined.

Tony Hoare, a British Computer Scientist who passed away back in March (bro was a Knight!) is credited for inventing null. The idea of null was “How do I represent something that isn’t there?” The issue was implementations of this idea caused computers to crash. A lot. Dynamic languages like JavaScript had their crashes far away from where the null entered the system making it harder to debug.

In the 1970’s Meta Language crew created an Option type (think of it like a Result):

type Option<T> = Some | None

type Some<T> = { tag: 'Some', data: T }
type None = { tag: 'None' }Code language: HTML, XML (xml)

Created as a Discriminated Union this ensured all null’s were forced to be handled before you could compile. This effectively “fixed” Tony’s “1 billion dollar mistake”. Other languages over the decades have implemented their own version of this, like Haskell calling it Maybe (e.g. Just<T>, Nothing) w/Monad powers.

Modern language type systems fixed some of their type lies, like Java saying “it’s a string… but jk, it can be null too”.

String greeting = "Hello, World!";
// in older Java, was basically string | nullCode language: JavaScript (javascript)

Even Dart did this, effectively removing null pointers. TypeScript, Python, and Luau arrived at something similiar when they implemented unions, and those unions were allowed to be anonymously defined:

type ReadEnvironmentVariable = (name:string) =>
  string | undefinedCode language: JavaScript (javascript)

Notice string | undefined isn’t defined anywhere; it’s just an anonymous type you defined. You could name it (which I encourage):

type EnvironmentVariableMaybe = string | undefinedCode language: JavaScript (javascript)

But because it was _so easy_ to define Maybe types like that, and TypeScript implemented a strict option, you started seeing null pointers just disappear except in places where developers intentionally turned off the type system (casting using as, using any, etc).

Using Maybe follows a Gartner Hype cycle: you learn about, realize all null pointers never happen anymore (no undefined is not a function). Then you realize “oh gawd, I have to provide defaults, and handle all these unhappy paths”. So you then swear them off, never allowing optional values. Then you realize things like environment variables _have_ to be optional. Finally, you realize Maybe/Option types are a lot like side-effects in Functional Core, Imperative Shell style architecture, like side-effects to be pushed to the edges of your code base, clearly indicating danger areas to be modeled.

Modern FP languages like Roc don’t even include it. It was common to model null with a Union type of “data or null” called Option or Maybe. You’ll learn to avoid if possible as it’s better to use a Result.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *