165

Why are people always using enum values like 0, 1, 2, 4, 8 and not 0, 1, 2, 3, 4?

Has this something to do with bit operations, etc.?

I would really appreciate a small sample snippet on how this is used correctly :)

[Flags]
public enum Permissions
{
    None   = 0,
    Read   = 1,
    Write  = 2,
    Delete = 4
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Pascal
  • 12,265
  • 25
  • 103
  • 195
  • 1
    possible duplicate of [Enum as Flag using, setting and shifting](http://stackoverflow.com/questions/581555/enum-as-flag-using-setting-and-shifting) – H H Mar 21 '12 at 21:52
  • 27
    I disagree on the dupe vote. – zzzzBov Mar 21 '12 at 22:08
  • UNIX way to set permission is also based on the same logic. – Rudy Mar 22 '12 at 06:52
  • 3
    @Pascal: You may find it helpful to read about [Bitwise OR](http://en.wikipedia.org/wiki/Bitwise_operation#OR) (and [Bitwise AND](http://en.wikipedia.org/wiki/Bitwise_operation#AND) ), which is what `|` (and `&`) represent. The various answers assume you are familiar with it. – Brian Mar 22 '12 at 13:42
  • @Pascal: If you don't use powers of 2, if you have, let's say `4` you wouldn't be able to differenciate between `1 + 3` and a plain `4` – Mosty Mostacho Mar 22 '12 at 14:46
  • possible duplicate of [Enum Flags Attribute](http://stackoverflow.com/questions/8447/enum-flags-attribute) – IAdapter Mar 27 '12 at 22:17
  • 2
    @IAdapter I can see why you'd think that, as the answer to both are the same, but I think the questions are different. The other question just asks for an example or explanation of the Flags attribute in C#. This question seems to be about the concept of bit flags, and the fundamentals behind them. – Jeremy S Mar 28 '12 at 17:28

7 Answers7

272

Because they are powers of two and I can do this:

var permissions = Permissions.Read | Permissions.Write;

And perhaps later...

if( (permissions & Permissions.Write) == Permissions.Write )
{
    // we have write access
}

It is a bit field, where each set bit corresponds to some permission (or whatever the enumerated value logically corresponds to). If these were defined as 1, 2, 3, ... you would not be able to use bitwise operators in this fashion and get meaningful results. To delve deeper...

Permissions.Read   == 1 == 00000001
Permissions.Write  == 2 == 00000010
Permissions.Delete == 4 == 00000100

Notice a pattern here? Now if we take my original example, i.e.,

var permissions = Permissions.Read | Permissions.Write;

Then...

permissions == 00000011

See? Both the Read and Write bits are set, and I can check that independently (Also notice that the Delete bit is not set and therefore this value does not convey permission to delete).

It allows one to store multiple flags in a single field of bits.

Ed S.
  • 122,712
  • 22
  • 185
  • 265
  • Just as a side note, in Java a collection of enums is where EnumSet comes in handy instead of a bit field. C# probably has an analogue, maybe it's worth mentioning in the answer. – Malcolm Mar 21 '12 at 23:31
  • 2
    @Malcolm: It does; `myEnum.IsSet`. I am of the opinion that this is a completely useless abstraction and serves only to cut down typing, but meh – Ed S. Mar 21 '12 at 23:42
  • 1
    Good answer, but you should mention why the Flags attribute is applied, and when you wouldn't want to apply Flags to some enums as well. – Andy Mar 22 '12 at 00:20
  • 3
    @Andy: Actually, the `Flags` attribute does little more than give you 'pretty printing' iirc. You can use an enumerated value as a flag regardless of the presence of the attribute. – Ed S. Mar 22 '12 at 00:21
  • Not quite accurate. C# may not care, but trying to use enums without Flags in VB doesn't seem to work: http://stackoverflow.com/questions/5902967/what-does-the-flags-attribute-really-do – Andy Mar 22 '12 at 00:34
  • @Andy: Well, I don't use VB, so I wouldn't know. I gave a C# answer because the question is tagged C#, but it is interesting that they would differ. – Ed S. Mar 22 '12 at 00:39
  • Why not just `permissions & Permissions.Write`? (I don't really know C#, just C, so maybe it's a language difference?) – detly Mar 22 '12 at 01:15
  • 3
    @detly: Because if statements in C# require a boolean expression. `0` is not `false`; `false` is `false`. You could however write `if((permissions & Permissions.Write) > 0)`. – Ed S. Mar 22 '12 at 01:35
  • @EdS. Ah, of course, I was still thinking in C, where there's no real boolean type. – detly Mar 22 '12 at 01:45
  • @EdS. Josh Bloch doesn't agree with you in Item 32 of the Effective Java. It is not only less typing, but also less error-prone, and easier to use because instead of working with bitwise operations you work with collections. – Malcolm Mar 22 '12 at 06:43
  • @EdS. Understood, but while the question is about C# that doesn't mean the poster isn't doing things that need to be CLS complaint and visible in other languages. – Andy Mar 22 '12 at 13:43
  • @Malcolm: Well, whether Josh Bloch agrees with me or not, this is a personal opinion, and I don't see the value in hiding such a simple operation behind a method. That operation is never going to change, and honestly, any half way decent programmer should be able to AND a couple of variables without issue. I don't buy the "less error prone" argument. – Ed S. Mar 22 '12 at 16:53
  • @EdS. To AND a few constants is not a problem, but what about adding a range of flags, iterating over a set of flags, or printing it? And also nothing prevents from adding a wrong constant to a bit field, because there's no type checking. So I see no benefits in using bit fields except when you need to work with serialization, for example. This is just a suggestion, of course, the answer is yours, and you don't have to add something based on my opinion. – Malcolm Mar 22 '12 at 17:32
  • @Malcolm: I guess I don't understand. Adding a range of flags? Ok; `flags = Flag.First | Flag.Second | Flag.Third`. Not hard or any more error prone than calling a method. How does a method prevent you from adding the wrong value? I also don't understand this; *"So I see no benefits in using bit fields except when you need to work with serialization"* - Really? You would rather define a property on a type for *every possible value*? I don't get it. – Ed S. Mar 22 '12 at 18:57
  • @EdS. Adding a range of flags: that's for three of them, what if you have much more? Try to replace `EnumSet.range(Flag.FIRST, Flag.FOURTEENTH)`. Prevention of wrong values: you have an `EnumSet field` and you have enum `Flag` and `AnotherFlag`. You can't add constants from `AnotherFlag` to field, but you could if you had `int field`. As for the properties, you don't need to define any properties, you only replace the bit field with an EnumSet. Maybe I didn't quite get your point, can you elaborate? – Malcolm Mar 22 '12 at 19:46
  • @Malcolm: OK, I misunderstood you initially as I don't know Java. I thought `BitSet(somFlag)` was a function that returned a boolean depending on whether or not the value was present, i.e., `if(permissions.BitSet(someValue))`. It is actually representative of a *set of bits*, where more than just the check above is abstracted away from you. – Ed S. Mar 22 '12 at 19:58
  • @EdS. Yes, exactly. In turn, I'm not really familiar with C#, so that's why I don't know whether my suggestion based on Java is valid here. Glad that we've cleared up this misunderstanding. – Malcolm Mar 22 '12 at 20:06
  • 2
    Instead of the 'tricky' `(permissions & Permissions.Write) == Permissions.Write`, you can now use `enum.HasFlag()` – Louis Kottmann Oct 23 '12 at 12:21
  • @Baboon: Yes, it's more consise which is nice, but you'll have to try harder to convince me that basic bitwise operations are "tricky" :) – Ed S. Oct 23 '12 at 16:50
  • @EdS. Hence the quotes ;) but admit that the first time it's not so obvious. – Louis Kottmann Oct 23 '12 at 22:36
151

If it is still not clear from the other answers, think about it like this:

[Flags] 
public enum Permissions 
{   
   None = 0,   
   Read = 1,     
   Write = 2,   
   Delete = 4 
} 

is just a shorter way to write:

public enum Permissions 
{   
    DeleteNoWriteNoReadNo = 0,   // None
    DeleteNoWriteNoReadYes = 1,  // Read
    DeleteNoWriteYesReadNo = 2,  // Write
    DeleteNoWriteYesReadYes = 3, // Read + Write
    DeleteYesWriteNoReadNo = 4,   // Delete
    DeleteYesWriteNoReadYes = 5,  // Read + Delete
    DeleteYesWriteYesReadNo = 6,  // Write + Delete
    DeleteYesWriteYesReadYes = 7, // Read + Write + Delete
} 

There are eight possibilities but you can represent them as combinations of only four members. If there were sixteen possibilities then you could represent them as combinations of only five members. If there were four billion possibilities then you could represent them as combinations of only 33 members! It is obviously far better to have only 33 members, each (except zero) a power of two, than to try to name four billion items in an enum.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 35
    +1 for the mental image of an `enum` with four billion members. And the sad part is, probably somebody out there has tried it. – Daniel Pryden Mar 21 '12 at 22:53
  • 24
    @DanielPryden As a daily reader of Daily WTF, I'd believe it. – fluffy Mar 22 '12 at 04:19
  • 1
    2^33 = ~8.6 billion. For 4 billion different values you only need 32 bits. – user Mar 22 '12 at 08:27
  • 6
    @MichaelKjörling one of the 33 is for the 0 default – ratchet freak Mar 22 '12 at 09:24
  • @MichaelKjörling: To be fair, there are only 32 members which are powers of 2, since 0 is not a power of two. So "33 members, each one a power of two" is not precisely correct (unless you count `2 ** -infinity` as a power of two). – Brian Mar 22 '12 at 20:13
  • If using bitwise operations wouldn't it limit the amount of enum members to 32 assuming we start at 1? The 32nd member would have the (binary) value 10000000000000000000000000000000. N members would equal N bits or am I incorrect? – Joel Peltonen Aug 08 '12 at 10:11
  • @Nenotlep 32 positions of 1 in each position, yes, but the 33rd is all 0s, with 1 never appearing. ;-) – Louis St-Amour Apr 19 '14 at 01:22
37

Because these values represent unique bit locations in binary:

1 == binary 00000001
2 == binary 00000010
4 == binary 00000100

etc., so

1 | 2 == binary 00000011

EDIT:

3 == binary 00000011

3 in binary is represented by a value of 1 in both the ones place and the twos place. It is actually the same as the value 1 | 2. So when you are trying to use the binary places as flags to represent some state, 3 isn't usually meaningful (unless there is a logical value that actually is the combination of the two)

For further clarification, you might want to extend your example enum as follows:

[Flags]
public Enum Permissions
{
  None = 0,   // Binary 0000000
  Read = 1,   // Binary 0000001
  Write = 2,  // Binary 0000010
  Delete = 4, // Binary 0000100
  All = 7,    // Binary 0000111
}

Therefore in I have Permissions.All, I also implicitly have Permissions.Read, Permissions.Write, and Permissions.Delete

Chris Shain
  • 50,833
  • 6
  • 93
  • 125
  • and what is the problem with 2|3 ? – Pascal Mar 21 '12 at 19:05
  • 1
    @Pascal: Because `3` is `11` binary, i.e., it does not map to a single set bit, so you lose the ability to map 1 bit in an arbitrary position to a meaningful value. – Ed S. Mar 21 '12 at 19:08
  • 8
    @Pascal put another way, `2|3 == 1|3 == 1|2 == 3`. So if you have a value with binary `00000011`, and your flags included values `1`, `2`, and `3`, then you wouldn't know if that value represents `1 and 3`, `2 and 3`, `1 and 2` or `only 3`. That makes it a lot less useful. – yshavit Mar 21 '12 at 20:00
11
[Flags]
public Enum Permissions
{
    None   =    0; //0000000
    Read   =    1; //0000001
    Write  = 1<<1; //0000010
    Delete = 1<<2; //0000100
    Blah1  = 1<<3; //0001000
    Blah2  = 1<<4; //0010000
}

I think writing using a binary shift operator << is easier to understand and read, and you don't need to calculate it.

surfmuggle
  • 5,527
  • 7
  • 48
  • 77
Dozer
  • 5,025
  • 11
  • 36
  • 52
5

These are used to represent bit flags which allows combinations of enum values. I think it's clearer if you write the values in hex notation

[Flags]
public Enum Permissions
{
  None =  0x00,
  Read =  0x01,
  Write = 0x02,
  Delete= 0x04,
  Blah1 = 0x08,
  Blah2 = 0x10
}
Adam Caviness
  • 3,424
  • 33
  • 37
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • well int "16" is more readable than hex "0x10" for me with int I know its always the double value 2 to 4, 4 to 8, 8 to 16, 16 to 32 etc.. with hex I do not know that, maybe also I am not firm with hex values. – Pascal Mar 21 '12 at 19:09
  • 4
    @Pascal: Perhaps it is more readable to you at this point in time, but as you gain experience viewing bytes in hex becomes second nature. Two digits in hex maps to one byte maps to 8 bits (well... a byte is usually 8 bits anyway... not always true, but for this example it is ok to generalize). – Ed S. Mar 21 '12 at 19:11
  • 5
    @Pascal quick, what do you get when you multiply `4194304` by 2? How about `0x400000`? It's much easier to recognize `0x800000` as the correct answer than `8388608`, and it's also less error-prone to type the hex value. – phoog Mar 21 '12 at 20:43
  • 6
    It's a lot easier to tell, at a glance, if your flags are set properly (i.e., are powers of 2), if you use hex. Is `0x10000` a power of two? Yes, it starts with 1, 2, 4, or 8 and has all 0s afterwards. You do not need to mentally translate 0x10 to 16 (though doing so will probably become second nature eventually), just think of it as, "some power of 2". – Brian Mar 21 '12 at 21:40
  • 1
    I'm absolutely with Jared about it being much easier to note in hex. you just use 1 2 4 8 and shift – bevacqua Mar 22 '12 at 01:13
  • 1
    Personally, I prefer just using e.g. P_READ=1<<0, P_WRITE=1<,1, P_RW = P_READ|P_WRITE. I'm not sure if that sort of constant-folding works in C# but it works just fine in C/C++ (as well as Java, I think). – fluffy Mar 22 '12 at 04:18
1

Lot's of good answers to this one… I'll just say.. if you do not like, or cannot easily grasp what the << syntax is trying to express.. I personally prefer an alternative (and dare I say, straightforward enum declaration style)…

typedef NS_OPTIONS(NSUInteger, Align) {
    AlignLeft         = 00000001,
    AlignRight        = 00000010,
    AlignTop          = 00000100,
    AlignBottom       = 00001000,
    AlignTopLeft      = 00000101,
    AlignTopRight     = 00000110,
    AlignBottomLeft   = 00001001,
    AlignBottomRight  = 00001010
};

NSLog(@"%ld == %ld", AlignLeft | AlignBottom, AlignBottomLeft);

LOG 513 == 513

So much easier (for myself, at least) to comprehend. Line up the ones… describe the result you desire, get the result you WANT.. No "calculations" necessary.

Alex Gray
  • 16,007
  • 9
  • 96
  • 118
1

This is really more of a comment, but since that wouldn't support formatting, I just wanted to include a method I've employed for setting up flag enumerations:

[Flags]
public enum FlagTest
{
    None = 0,
    Read = 1,
    Write = Read * 2,
    Delete = Write * 2,
    ReadWrite = Read|Write
}

I find this approach especially helpful during development in the case where you like to maintain your flags in alphabetical order. If you determine you need to add a new flag value, you can just insert it alphabetically and the only value you have to change is the one it now precedes.

Note, however, that once a solution is published to any production system (especially if the enum is exposed without a tight coupling, such as over a web service), then it is highly advisable against changing any existing value within the enum.

Mike Guthrie
  • 4,029
  • 2
  • 25
  • 48