> Typestate improves code faultlessness and testability, but comes at the cost of more boilerplate code and can degrade readability.
I have noticed this in my own code. `Ticket` with an internal variable tracking the state makes using it simpler. I just have to store one object in my struct `struct MyData { ticket: Ticket }` and call `ticket` methods in the correct order.
Typestate `Ticket<T>` is not as simple. I have to wrap it in my own enum: `enum TicketState { Ticket1(Ticket<Func1Done>), Ticket2(Ticket<Func2Done>), }` to store in my struct: `struct MyData { ticket: TicketState }`. Then every time I call `ticket` methods, I must extract the correct variant value first. That degrades readability and creates extra run-time cost.
It's really not that cumbersome, it's like two extra lines of code...
pub trait ValidState {}
struct StateMachine<'a, T>
where
T: ValidState
{untyped: &'a mut UntypedStateMachine,
_marker: PhantomData<T>
}
fn reserve_right<'a>(state: StateMachine<'a, Begin>) -> StateMachine<'a, Reserved>
fn query<'a>(state: StateMachine<'a, Reserved>) -> StateMachine<'a, Queried>
fn record<'a>(state: StateMachine<'a, Queried>) -> StateMachine<'a, Recorded>