- ReasonML Quick Start Guide
- Raphael Rafatpanah Bruno Joseph D'mello
- 355字
- 2021-07-02 12:34:15
Making Invalid States Impossible
Let's say that we'd like to add a field to seat to hold the date a seat was purchased:
type seat = {
section,
price: int,
person: option(person),
dateSold: option(string)
};
Now, we've introduced the possibility of an invalid state in our code. Here's an example of such a state:
let seat = {
section: Pit,
price: 42,
person: None,
dateSold: Some("2018-07-16")
};
In theory, the dateSold field should only hold a date when the person field holds a ticket holder. The ticket has a sold date, but no owner. We could look through our imaginary implementation to verify that this state would never happen, but there would still be the possibility that we missed something, or that some minor refactor introduced a bug that was overlooked.
Since we now have the power of Reason's type system at our disposal, let's offload this work to the compiler. We are going to use the type system to enforce invariants in our code. If our code breaks these rules, it won't compile.
One giveaway that this invalid state could exist is the use of option types within our record field. In these cases, there may be a way to use a variant instead such that each constructor only holds the relevant data. In our case, our sold-date and ticket-holder data should only exist when the seat has been sold:
type person = {
age: int,
name: string,
};
type date = string;
type section =
| Pit
| Floor
| Mezzanine
| Balcony;
type status =
| Available
| Sold(date, person);
type seat = {
section,
price: int,
status
};
let getSeatPrice = (seat) => seat.price;
let isAvailable = (seat) =>
switch (seat.status) {
| Available => true
| Sold(_) => false
};
Check out our new status type. The Available constructor holds no data, and Sold holds the sold date as well as the ticket holder.
With this seat type, there's no way to represent the previous invalid state of having a sold date without a ticket holder. It's also a good sign that our seat type no longer includes option types.