C++ Type-Driven Design
Core Question
Can I make this bug a compile error?
- •Primitive Obsession: Using
intfor IDs,doublefor Money. Bad. - •Strong Types:
struct UserId,struct Money. Good. - •Type State:
Connection<OFF>vsConnection<ON>.
Error → Design Question
| Issue | Design Question |
|---|---|
| Swapped arguments | Did you pass width to height? (Use Strong Types). |
| Invalid State | Did you call read() on closed file? (Use Type State). |
| Unit confusion | Did you mix Meters and Feet? (Use std::chrono style units). |
Thinking Prompt
- •
Is this
intunique?- •Yes? → Wrap in
struct. - •
struct UserId { int val; };preventsprocess(OrderId).
- •Yes? → Wrap in
- •
Does valid usage depend on order?
- •Yes? → Encode state in type.
- •
Builder::port()returnsBuilderWithPort.
- •
Are units compatible?
- •No? → Template tag.
Dist<Meters>+Dist<Feet>.
- •No? → Template tag.
Trace Up / Down
- •
Trace Up:
- •Issue: "Rocket crashed because of Metric vs Imperial confusion."
- •Cause:
double calculate_trajectory(double dist)accepted any number. - •Fix:
Dist<Meters> calculate(Dist<Meters> d). Compilation fails if you pass Feet.
- •
Trace Down:
- •Intent: "Ensure file is open before reading."
- •Code:
File<Open> f = File<Closed>().open(); f.read();
Quick Reference
| Pattern | Cost | Use When |
|---|---|---|
| Struct Wrapper | Zero | Distinct IDs, coordinates. |
| Enum Class | Zero | Type-safe flags (no implicit int conv). |
| Phantom Type | Zero | Tracking state without storage. |
| User Literal | Zero | 10_m, 50_s. |