My Terribly Clever(ly Terrible) Code
I started learning C++ in graduate school. I had written Python for five years, so I thought I was pretty good at writing code and thinking through problems.1 Like many new programmers I enjoyed finding clever solutions to problems; sometimes too clever. This is the story of one of those times.
The Problem
I had to handle setting some state based on two variables. Each variable could take one of a few discrete values. For simplicity, think of the variables and possible values:
Variable Name | Possible Values |
---|---|
direction | north , east , south , west |
travel_mode | bike , car , plane |
All twelve combinations required doing something slightly different, so the first code I wrote looked something like this:
if (direction == "north" && travel_mode == "bike") {
do_north_bike_stuff();
}
else if (direction == "north" && travel_mode == "car") {
do_north_car_stuff();
}
else if ( ... ) {
... // etc.
}
This code wasn’t clever; it was boring and repetitive so I looked for a way to rewrite it! I had recently learned about a cool way to replace if/else
in C++: the switch
statement. I had to use it!
Making It Worse
But a switch
statement needs integral values, so I had to map each state to numbers. Easy enough, but I quickly ran into a problem: I had to switch based on both values, so I had to combine the integers in some manner. Then I remembered a “useful” math fact: the product of unique primes is itself unique.2 A horrible plan came together, it looked like this:
int NORTH = 2;
int EAST = 3;
int SOUTH = 5;
int WEST = 7:
int BIKE = 11;
int CAR = 13;
int PLANE = 17;
switch(direction * travel_mode) {
case NORTH * BIKE: do_north_bike_stuff(); break;
case EAST * BIKE: do_east_bike_stuff(); break;
... // etc.
case WEST * PLANE: do_west_plane_stuff(); break;
}
My code was actually even worse; if you are morbidly curious I archived it here. I did not assign nice readable variables like NORTH
but just used the numbers, so it looked like case 2 * 11: do_north_bike_stuff()
.
This code is way too clever; needing number theory to understand control flow is a huge warning sign. With ten years more experience, I actually prefer the verbose but understandable if/else
method.
A Better Way
So how would I write it now? I think a hybrid method is actually the way to go, using enum
3 and a few helper functions:
enum TravelMode { BIKE, CAR, PLANE };
enum Direction { NORTH, EAST, SOUTH, WEST };
switch(travel_mode) {
case BIKE: do_bike_stuff(direction); break;
case CAR: do_car_stuff(direction); break;
case PLANE: do_plane_stuff(direction); break;
}
void do_bike_stuff(Direction dir) {
switch(dir) {
case NORTH: ...; break;
case EAST: ...; break;
... // etc.
}
}
This has a few nice advantages:
- It delegates the complexity of handling the direction to each travel mode. This is logical because it’s likely the way a car handles East and West are very similar, and very different from how a plane would.
- By using
enum
the compiler can check that we handle every case. If we forgetcase BIKE
orcase EAST
, the compiler can warn us.
In the end, readable is better than clever, even if you have a bunch more lines to read!
-
Narrator: He wasn’t. ↩
-
Narrator: It was not useful. ↩
-
See Python Patterns: Enum, which covers use-cases for
enum
in Python. It works essentially the same in C++. ↩