Enumerations allow you to name different related options. The names can refer to a single option or you can use what you now know about bits to combine them into flags. With flags, you can have multiple enumeration options that you can work with as a single value.
Whether you want to keep track of colors with enumeration values red, green, blue, etc. or you want to keep track of what a piece of armor is made out of as this episode describes, enumerations allow you to provide more meaningful names to these values.
It’s a lot more readable and less error prone than returning an integer directly and then trying to remember what value that integer represents. Give your values actual names with an enumeration.
Enumerations declared like this can only take on a single value at a time. In other words, the color can be either red, or it can be blue, etc. But it can’t be both red and blue.
At least not with a simple enumeration. If you instead carefully choose the numeric values for each value name so that the numeric values don’t conflict with one another at the binary level, then they can be combined.
This is called a flag based enumeration and the enumeration values themselves are called flags. You choose values so they each have a single 1 binary digit and make sure that each flag value uses a different binary digit. You’ll want to use powers of two since these are the values that align with the binary place holder positions.
Should your first flag be given the value of zero? Well, only if you want or need to be able to express the concept that none of the other flags currently apply. That could be important and if so, you probably want to consider naming this value “none” or “empty” or something that conveys the meaning of an absence of a value.
You might also want to define enumeration values that are not intended to be used as flags but as a mask in case you need to work with certain groups of flags. Maybe certain flag combinations have special meaning or you just want to categorize them. The episode explains more about this. You can listen to the full episode or read the full transcript below.
This is a common design decision especially with object-oriented programming. For example, should you have a base class called Armor and then separate derived classes for LeatherArmor, ChainArmor, or SteelArmor? Or should you just have a single class called Armor that know what type of armor it is? There’s no right answer and it will depend on your situation.
If you decide to go with the second approach and have just a single Armor class, then how will you express the type of armor?
One approach that I don’t recommend is you could have methods called isLeather, isChain, and isSteel that each return a boolean true or false. This imposes a horrible experience for any code trying to use your class because it has to call each of these methods one after another until one of them returns true. Imagine trying to play 20 questions with a 5 year old. Is it a dog? No. Is it a cat? No. Is it a tree? No.
And what do you do when a new kind of armor comes along? Say DragonArmor. You now have to add a new method isDragon and then modify all the other code to start probing for this new type as well.
A much better approach is to create a new type called an enumeration. This is a custom user-defined type just like how your classes are types. But instead of being able to add a bunch of data and methods to an enumeration, all it does is provide you with a means to map your own names to values.
Enumerations don’t support multiple values. What I mean is that you can’t have an enumeration with some ints and a char and maybe a few bools. That would be a class. An enumeration has just a single value type and it gives you the ability to name specific values.
With the Armor example, what we need is an enumeration called ArmorType. And we can then add values leather, chain, and steel. If you don’t specify specific values for the names you provide, then the compiler will generate unique values for you usually starting with zero. Or you can give your own values. Or you can give just a single value and the following names will each have a value that’s one greater than the previous name. So if we don’t specify anything other than we have the three values leather, chain, and steel, then the compiler will likely assign zero for leather, one for chain, and two for steel.
Once you have the ArmorType enumeration declared, you then add a method to your Armor class maybe called material that returns an ArmorType. Now the other code using your Armor class doesn’t have to call a bunch of methods to figure out what the armor is made of. It just calls the one method material that returns an ArmorType enumeration. This return type will be a numeric value that matches one of the values specified in the enumeration declaration.
When it comes time to add that new DragonArmor, you add a new dragon value to the ArmorType enumeration and the Armor class can start using it. Sure, the other code that uses the Armor class also needs to be modified if it wants to take advantage of the new material but the main thing is that there was no need to add a new set of methods to the Armor class. It’s just a new possible value that can be returned now by the material method.
Flags are really just a special use of enumerations and I’ll explain them right after this message from our sponsor.
( Message from Sponsor )
If you let the compiler provide its own numeric values for the enumeration names or the enumeration values, then you’ll get consecutive values usually starting from zero. Your enumeration then becomes a choice. The armor is either leather, chain, steel, or dragon. It can’t be both leather and steel.
But if you provide your own values and you do so in a clever way so that they don’t interfere with each other, then they can be combined. What do I mean by this? This allows you to specify both leather and steel. Or you can combine more than just two and maybe have chain, steel, and dragon.
Some languages might ask you to take a few extra steps but in general, all you have to do to declare flags is carefully choose the numeric values for each name so that only a single binary bit is used. Then make sure that each name uses a different binary bit.
Let me show you some binary numbers with leading zeros. I’ll just go through eight values which requires three binary digits.
◦ 000 – This is of course 0 and could be a good choice only if you wanted your Armor to possibly be made of nothing. That’s not likely. In general, this is a good choice when you want to convey the idea that none of the values apply.
◦ 001 – This is 1 and uses just a single bit. This is a great choice for your first flag.
◦ 010 – This is 2 and is another great choice for a flag.
◦ 011 – This is 3 and should not be used for a flag because it has two digits set to 1. It cannot exist without interfering with 2 and 1.
◦ 100 – This is 4 and is another great choice for a flag because it only has a single digit with a 1.
◦ 101 – This is 5 and is no good. It conflicts with 4 and 1.
◦ 110 – This is 6 and is no good. It conflicts with 4 and 2.
◦ 111 – This is 7 and is definitely no good. It conflicts with 4, 2, and 1.
As you can see, there are few binary values that work well for flags and these are 1, 2, 4, and if you continue, then 8, 16, 32, etc. In other words, the powers of 2 all use just a single binary digit and are great choices for flags.
If you have an enumeration that uses a byte value for holding the enumeration values, then because a byte has 8 bits, that means you can only have a maximum of 8 flags. Each flag uses just a single bit and you have 8 bits so that gives you 8 values.
That may not seem like a lot but you can combine these 8 values in many different combinations. That gives you some serious flexibility. You’ve got a possible 28 different combinations with just combining 2 flags. And this doesn’t even begin to cover the extra combinations that might use 3 flags or 4 flags, etc.
Most enumerations will likely be using an integer for the underlying storage. With 32 bit integers, you can define up to 32 unique flags that each use a single binary digit.
Alright, so you can specify enumeration values now that don’t overwrite other enumeration values, how do you use this capability?
The first thing to realize is that when working with simple enumerations that can only have a single value at any given time, it’s okay to assign values directly. So you can say in your code that the material is assigned the value leather. Or you can check to see if the material equals leather in an if statement.
But with flags, you have to use bitwise operations. That’s why I waited to introduce enumerations and especially flag enumerations until after the recent episodes on bit operations. You see, with flags, you have to mask the other values so you can test just the values you want.
Let’s say you want to find out if some armor is made of leather, you can’t just test the material by saying:
◦ if (material == leather)
because this will only work when the armor is made of leather and only leather. If the armor happens to be made of both leather and steel, then your if statement will fail.
You have to change your code to say:
◦ if (material & leather == leather)
This will mask out all the other material types first before comparing the result with leather and will then properly let you know if the armor contains leather. Of course, if you really want to know if the armor is leather and nothing else, just leather only, then the first code that compares the material with leather is what you want.
I mentioned earlier how enumeration values that contain more than a single bit are no good. That’s true for the individual enumeration flag values that need to be able to be combined without interfering with one another.
Now, I’m going to backtrack a bit and tell you how they might actually be useful after all. Let’s say that you not only have individual flag values but also want to categorize them into other groups. For example, both leather and dragon come from living creatures. At least living creatures in the game you’re working on. And both chain and steel are metallic. You could create an enumeration value that combines leather and dragon and maybe call it organic and another one called metallic that combines both chain and steel.
Now you wouldn’t want to use these new organic and metallic values when setting the type of armor material. The actual material should still only ever use the unique values that don’t conflict. These new values are just categories and are great at testing multiple values at once like this:
◦ if (material & organic != 0)
An if statement like that is a great way to test for leather or dragon or both leather and dragon when you don’t really care about the specific type but are more interested in what category the type belongs to.
All in all, enumerations, and flag based enumerations are extremely powerful and flexible tools that will greatly simplify your code and give it a much more usable design.