Every now and then I have peaked at Haskell Tutorials and found the Algebraic data types quite interesting. I took their purpose to be to represent types that have completely separable states. Sadly, I never got to write more Haskell than tutorial level projects, and so I never had to really design programs using this pattern.
Now I am writing some Rust, and I have algebraic datatypes (enums) in the toolbox. However, I am not very confident in using them.
Let me start with an example where I am confident that such an enum is a proper choice.
enum Tree {
Leaf(i: String),
Branch(Tree, Tree)
}
The same example would be applicaple for an XML-like structures, etc.
With other data, I am not so confident about using enum types. Let's take a connection object
enum Connection {
UnConnected(...),
ConnectedConnection(....)
}
Here we would have a Connection type with two possible values, one representing the state where a connection is not yet established, the other one could represent the state of a connected connection (and wrapping a connection handle for example).
The other possibility would be to introduce 2 types for a Connection-Template and a connected connection.
Another example that I found in rust code is that in the hyper
library. There is the type Response
that represents a HTTP response. It is a generic type.
Response<Fresh>
represents the state where headers are not yet frozen. Once upon it is mapped to a Response<Streaming>
, which can be used to write the body of the response. It seems like what Hyper models here with different types (Response<Fresh>
vs Response<Streaming>
) could have been modeled with enum
types as well.
The approach with different types allows for more safety, Response<Fresh>
does not implement streaming (I think) and Response<Streamimg>
does.
Do you know of guidelines and best practices that guide through modelling logic in types properly?