Here’s another useful Rust pattern. Like the Typestate Pattern
before it, I wrote this because I haven’t seen the sort of obsessively nerdy
writeup that I wanted to read. And, as with the Typestate Pattern, I didn’t
invent this — I’m merely documenting and generalizing it.
The typestate pattern is an API design pattern that encodes information about
an object’s run-time state in its compile-time type. In particular, an API
using the typestate pattern will have:
Operations on an object (such as methods or functions) that are only available
when the object is in certain states,
A way of encoding these states at the type level, such that attempts to use
the operations in the wrong state fail to compile,
State transition operations (methods or functions) that change the
type-level state of objects in addition to, or instead of, changing run-time
dynamic state, such that the operations in the previous state are no longer
possible.
This is useful because:
It moves certain types of errors from run-time to compile-time, giving
programmers faster feedback.
It interacts nicely with IDEs, which can avoid suggesting operations that are
illegal in a certain state.
It can eliminate run-time checks, making code faster/smaller.
This pattern is so easy in Rust that it’s almost obvious, to the point that
you may have already written code that uses it, perhaps without realizing it.
Interestingly, it’s very difficult to implement in most other programming
languages — most of them fail to satisfy items number 2 and/or 3 above.
I haven’t seen a detailed examination of the nuances of this pattern, so here’s
my contribution.