To me, it means using types as an element of a state machine. Where in more traditional OO languages, I would have single classes that would move through stages of growth by having fields start null and become populated, in Rust I just have multiple related struct
s, and each stage of growth returns the next struct
in the line.
For example, FinalStruct::begin() -> FinalStructStage1;
makes an object with what state I have available at the beginning, then as I grow more information I have a FinalStructStage1::grow(self) -> FinalStructStage2;
method, rinse and repeat until FinalStructStageN::finish(self) -> FinalStruct;
The type checker therefore makes it impossible for me to have invalid object states, and I can tell by simple inspection where in the growth cycle I am at any point.
The only downside is that, in order to prevent a flood of intermediate types all with public visibility, I've been using a super-struct with a private enum
member that unifies the intermediate types, and all the intermediate growth methods implemented on the super-struct simply match on the current enum state to delegate or fail.
It'd be nice if Rust had "Voldemort types", where methods returning private symbols couldn't be bound directly, but could have methods called on them, until the chain eventually did return a public type.
pub struct Final {}
struct Stage0 {}
struct Stage1 {}
impl Final { pub fn begin() -> Stage0 { Stage0 {} } }
impl Stage0 { pub fn grow(self) -> Stage1 { Stage1 {} } }
impl Stage1 { pub fn finish(self) -> Final { Final {} } }
let f = Final::begin(); // error: f is of type Stage0, which is not public
let f = Final::begin().grow(); // error: f is of type Stage1, which is not public
let f = Final::begin().grow().finish(); // ok: f is of type Final, which is public
I've been using this pattern to great success in my personal projects, where useful methods are only implemented on the complete type, but since I need to grow that type as information comes in, I have a type-checked state machine ensuring that each step is correct and I can only act on the finalized data.