Poorly handled enums can infect code with fragility and tight coupling like a digital Typhoid Mary.
Say you’re writing software that optimizes traffic flow patterns, and you need to model different vehicle types. So you code up something like this:
vehicle_type.h
enum VehicleType { eVTCar, eVTMotorcycle, eVTTruck, eVTSemi, };
Then you press your enum into service:
route.cpp
if (vehicle.vt == eVTSemi || vehicle.vt == eVTTruck) {
// These vehicle types sometimes have unusual weight, so we
// have to test whether they can use old bridges...
if (vehicle.getWeight() > bridge.getMaxWeight()) {
Quickly your enum becomes handy in lots of other places as well:
if (vehicle.vt == eVTMotorcycle) {
// vehicle is particularly sensitive to slippery roads
And…
switch (vehicle.vt) { case eVTTruck: case eVTSemi: // can't use high-occupancy/fuel-efficient lane case eVTMotorcycle: // can always use high-occupancy/fuel-efficient lane default: // can only use lane during off-peak hours }
Diagnosis
The infection from your enum is already coursing through the bloodstream at this point. Do you recognize the warning signs?
- Knowledge about the semantics of each member of the enum are spread throughout the code.
- The members of the enum are incomplete. How will we account for cranes and bulldozers and tractors and vans?
- Semantics are unsatisfying. We’re saying cars are never gas guzzlers or gas savers; what about massive old steel-framed jalopies and tiny new hybrids?
The infection amplifies when we want to represent the enum in a config file or a UI. Now we need to Continue reading