The easiest way to use types for this is to have separate types for (un)initialised values, e.g. instead of having a 'Database' with methods for 'connect', 'select', 'insert', etc. where the caller has to run 'connect' first, we instead split it into two so that the first object (e.g. 'DisconnectedDatabase') doesn't have any query methods, but does have the 'connect' method which returns a 'Database', and the query methods exist on that.
A few things to keep in mind when doing this:
- If we end up with a classes which only has a single method (e.g. 'DisconnectedDatabase' with only a 'connect' method), then it might be better as a standalone function, or a smart constructor, etc. ( http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom... )
- We can use this approach to prevent code being called prematurely (e.g. querying has to come after connecting), but we can't prevent code being called too late; e.g. trying to query after a 'Database::disconnect' method has been called. (This is where linear/uniqueness types, etc. can be used)