The awesomeness of Flags, the binary oriented .net enums

flags

If you are using .net, you must use occasionally (or more) enums when you have to use use a list of predefined permitted values. Flags is an other way to use enums with amazing possibilities. It's all about binary and this articles will explain you how and why...

When should you use Flags enums?

public enum Days 
{
  Monday = 0,
  Tuesday = 1,
  Wednesday = 2,
  Thursday = 3,
  Friday = 4,
  Saturday = 5,
  Sunday = 6
}

Usually, your enum based members will be one of these predefined values. Either Monday, Tuesday, or Friday but not several at the same time. That's the point. At a lower level, or when it comes to serialization, your member will always be considered as an integer, with the value given to the corresponding enum.

But sometimes, you need more than a list of unique values and switch cases to play with your data. You want your values to be still part of a defined list, but in a more complex way, where it can be a combination of these discrete values, like both Monday and Tuesday at the same time and have evolved behaviors. Here comes the Flags enums.

[Flags]
public enum GameRatings 
{
  PositiveMessage = 1,
  PositiveRoleModel = 2,
  EaseOfPlay = 4,
  Violence = 8,
  Scariness = 16,
  CrudeLanguage = 32,
  DrinkingDrugsSmoking = 64,
  Sex = 128
}

How does it work?

Basically, the [Flags] attribute doesn't change anything to your enum. The .net Framework will not behave differently, but the itellisense will provide you a more user-friendly way to set values:

var myGameRating = GameRatings.PositiveMessage | GameRatings.EaseOfPlay  | GameRatings.CrudeLanguage;

In this case, our game has 3 combined ratings simultaneously: PositiveMessage, EaseOfPlay and CrudeLanguage using the "|" (or) operator. (see bitwise operations)

However, your enum values should be only using powers of two values. As you may have understood, these power of two values allow you to make unique combination of values. If our example:

myGameRating = 1 + 4 + 32 = 37

The .net framework will set it internally as 37, and when reading the value, 37 can only be translated as the combination of 1 + 4 + 32. This is the exact purpose of binary code.

A quick binary code reminder

wiki_64Source: Binary number wikipedia article http://en.wikipedia.org/wiki/Binary_number

In the binary system, each digit represents an increasing power of 2, with the rightmost digit representing 20, the next representing 21, then 22, and so on. The equivalent decimal representation of a binary number is sum of the powers of 2 which each digit represents. For example, the binary number 100101 is converted to decimal form as follows:

1001012 = [ 1 × 25 ] + [ 0 × 24 ] + [ 0 × 23 ] + [ 1 × 22 ] + [ 0 × 21 ] + [ 1 × 20 ]
1001012 = [ 1 × 32 ] + [ 0 × 16 ] + [ 0 × 8 ] + [ 1 × 4 ] + [ 0 × 2 ] + [ 1 × 1 ]
1001012 = 3710

We can see in this example, each digit of the binary number represent one of the enums members.

Bitwise operations

To go further with the Flags capabilities, we will use bitwise operations. These operations, are used in every piece of electronics and are the fundamentals of any operating system.

 wiki_64Source: Bitwise operations wikipedia article
http://en.wikipedia.org/wiki/Bitwise_operation

NOT

The bitwise NOT, or complement, is a unary operation that performs logical negation on each bit, forming the ones' complement of the given binary value. Bits that are 0 become 1, and those that are 1 become 0. For example:

NOT 0111  (decimal 7)
  = 1000  (decimal 8)

AND

A bitwise AND takes two equal-length binary representations and performs the logical AND operation on each pair of the corresponding bits, by multiplying them. Thus, if both bits in the compared position are 1, the bit in the resulting binary representation is 1 (1 × 1 = 1); otherwise, the result is 0 (1 × 0 = 0). For example:

    0101 (decimal 5)
AND 0011 (decimal 3)
  = 0001 (decimal 1)

OR

A bitwise OR takes two bit patterns of equal length and performs the logical inclusive OR operation on each pair of corresponding bits. The result in each position is 1 if the first bit is 1 or the second bit is 1 or both bits are 1; otherwise, the result is 0. For example:

   0101 (decimal 5)
OR 0011 (decimal 3)
 = 0111 (decimal 7)

XAND, XOR, NAND and NOR

Theses operations, eXclusive AND, eXclusive OR, Not AND and Not OR, are often used in electronics and boolean algebra, but will not be covered in this article. You can read more about them in the wikipedia page.

Bit addition

As seen previously when we set the myGameRating variable, the OR operation was used to add the 3 different enum values to make the final composite value. Actually, the myGameRating variable is initially set to 0, then each of the enum values are added.

var myGameRating = GameRatings.PositiveMessage | GameRatings.EaseOfPlay  | GameRatings.CrudeLanguage;
   000001 (decimal 1  : PositiveMessage)
OR 000100 (decimal 4  : EaseOfPlay)
OR 100000 (decimal 32 : CrudeLanguage)
 = 100101 (decimal 37)

Bit masking

If you want to know if your enum member actually contains a specific enum value, you can use the AND operation to "mask" the unnecessary bits and see if your data matches the requirement.

Example: Does my GameRating member contains the Flag CrudeLanguage?
In other terms: Does 37 contains 32?

    100101 (decimal 37 : myGameRating)
AND 100000 (decimal 32 : CrudeLanguage)
  = 100000 (decimal 32)

The answer is yes, 37 contains 32 because the operation's result is greater than 0. In your code it will look like:

var myGameRating = GameRatings.PositiveMessage | GameRatings.EaseOfPlay | GameRatings.CrudeLanguage;

bool IsMyGameCrude = (myGameRating & GameRatings.CrudeLanguage) > 0;

Complement

The NOT operation will be written in .net as the tiled "~" character and mostly useful if you want to do bit subtraction.

var NoViolence = ~GameRatings.Violence;
NOT 001000 (decimal 8  : Violence)
  = 110111 (decimal -9 : NoViolence)

The origin of the -9 comes from the fact that the leftmost digit of the binary value is the sign ( + or - ) and because of the two's complement.

youtube_64The origin of the 2's complement is explained by Computerphile here: http://www.youtube.com/watch?v=lKTsv6iVxV4

(not all digits are shown here, remember your computer is working with 32 or 64 bits).

Bit subtraction

If you want to remove a specific enum value from your variable (without even knowing if it already contains this value), you can subtract it by doing a bitmask to the complement:

var myGameRating = GameRatings.PositiveMessage | GameRatings.EaseOfPlay | GameRatings.CrudeLanguage;

var myGameRatingWithoutCrude = myGameRating & ~GameRatings.CrudeLanguage;
// this value equals to GameRatings.PositiveMessage | GameRatings.EaseOfPlay
NOT 100000 (decimal 32  : CrudeLanguage)
  = 011111 (decimal -33 : NoCrudeLanguage)
AND 100101 (decimal 37  : myGameRating)
 =  000101 (decimal 5   : myGameRatingWithoutCrude)

Here for instance, if your value myGameRating was not containing the CrudeLanguage value, the operation wouldn't have changed anything but would have worked anyway.

Bitwise operations applied to Flags Enums

HasFlag()

Since the .net Framework 4.0, the enum class implements a method called HasFlag(enum). This method will return a boolean, true if your initial value includes all the Flags given as parameter. It is a simple bitmask operation and verifies if none of the Flags have been filtered.

Composite Flags

In your enum declaration you can add some composite values, more than the powers of 2. It will simplify your operations.

Here's a more complete enum declaration.

[Flags]
public enum GameRatings
{
  None = 0,
  PositiveMessage = 1,
  PositiveRoleModel = 2,
  EaseOfPlay = 4,
  Violence = 8,
  Scariness = 16,
  CrudeLanguage = 32,
  DrinkingDrugsSmoking = 64,
  Sex = 128,

  AllGoodThings = PositiveMessage | PositiveRoleModel | EaseOfPlay,

  ExtremeViolence = Violence | Scariness | CrudeLanguage | DrinkingDrugsSmoking | Sex,
  AllRatings = AllGoodThings | ExtremeViolence
}

And it allows you to do a such operation:

var myGameRating = GameRatings.PositiveMessage | GameRatings.PositiveRoleModel | GameRatings.EaseOfPlay | GameRatings.Scariness;

myGameRating.HasFlag(GameRatings.ExtremeViolence);
// returns false
myGameRating.HasFlag(GameRatings.AllGoodThings);
// return true
myGameRating &= ~GameRatings.AllGoodThings;
// now equals to Scariness only
myGameRating |= GameRatings.ExtremeViolence;
// now equals to ExtremeViolence, i.e. the last 5 values.
myGameRating |= GameRatings.AllGoodThings;
// now equals to AllRatings.

Conclusion

Flags are programming porn.
It helps you to save a lot of processing time and space. You can store in an SQL database a bigint (64 bits) as the equivalent of 63 booleans. Be careful though, you won't be able to deal with more than 63 different values (on a x64 server).
You can filter a massive list of thousands (and millions) of objects in a record time by using a simple operation instead of several if's.
It becomes very useful with Linq and is also recognized when doing LinqToSQL queries.

Thank you for reading and sharing this article.
Don't hesitate to comment. I may write a Part II about factoring boolean operations.

Aurelien Jacquot

Leave a Reply

Your email address will not be published.