Why do enum permissions often have 0, 1, 2, 4 values?

21,580

Solution 1

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.

Solution 2

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.

Solution 3

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

Solution 4

[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.

Solution 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
}
Share:
21,580

Related videos on Youtube

Pascal
Author by

Pascal

nothing here :p

Updated on March 19, 2022

Comments

  • Pascal
    Pascal about 2 years

    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
    }
    
    • Henk Holterman
      Henk Holterman about 12 years
    • zzzzBov
      zzzzBov about 12 years
      I disagree on the dupe vote.
    • Rudy
      Rudy about 12 years
      UNIX way to set permission is also based on the same logic.
    • Brian
      Brian about 12 years
      @Pascal: You may find it helpful to read about Bitwise OR (and Bitwise AND ), which is what | (and &) represent. The various answers assume you are familiar with it.
    • Mosty Mostacho
      Mosty Mostacho about 12 years
      @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
    • IAdapter
      IAdapter about 12 years
      possible duplicate of Enum Flags Attribute
    • Jeremy S
      Jeremy S about 12 years
      @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.
  • Pascal
    Pascal about 12 years
    and what is the problem with 2|3 ?
  • Ed S.
    Ed S. about 12 years
    @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.
  • Pascal
    Pascal about 12 years
    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.
  • Ed S.
    Ed S. about 12 years
    @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).
  • yshavit
    yshavit about 12 years
    @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.
  • phoog
    phoog about 12 years
    @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.
  • Brian
    Brian about 12 years
    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".
  • Daniel Pryden
    Daniel Pryden about 12 years
    +1 for the mental image of an enum with four billion members. And the sad part is, probably somebody out there has tried it.
  • Malcolm
    Malcolm about 12 years
    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.
  • Ed S.
    Ed S. about 12 years
    @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
  • Andy
    Andy about 12 years
    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.
  • Ed S.
    Ed S. about 12 years
    @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.
  • Andy
    Andy about 12 years
    Not quite accurate. C# may not care, but trying to use enums without Flags in VB doesn't seem to work: stackoverflow.com/questions/5902967/…
  • Ed S.
    Ed S. about 12 years
    @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.
  • bevacqua
    bevacqua about 12 years
    I'm absolutely with Jared about it being much easier to note in hex. you just use 1 2 4 8 and shift
  • detly
    detly about 12 years
    Why not just permissions & Permissions.Write? (I don't really know C#, just C, so maybe it's a language difference?)
  • Ed S.
    Ed S. about 12 years
    @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).
  • detly
    detly about 12 years
    @EdS. Ah, of course, I was still thinking in C, where there's no real boolean type.
  • fluffy
    fluffy about 12 years
    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
    fluffy about 12 years
    @DanielPryden As a daily reader of Daily WTF, I'd believe it.
  • Malcolm
    Malcolm about 12 years
    @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.
  • user
    user about 12 years
    2^33 = ~8.6 billion. For 4 billion different values you only need 32 bits.
  • ratchet freak
    ratchet freak about 12 years
    @MichaelKjörling one of the 33 is for the 0 default
  • Andy
    Andy about 12 years
    @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.
  • Ed S.
    Ed S. about 12 years
    @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.
  • Malcolm
    Malcolm about 12 years
    @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.
  • Ed S.
    Ed S. about 12 years
    @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.
  • Malcolm
    Malcolm about 12 years
    @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<Flag> 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?
  • Ed S.
    Ed S. about 12 years
    @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.
  • Malcolm
    Malcolm about 12 years
    @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.
  • Brian
    Brian about 12 years
    @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).
  • Joel Peltonen
    Joel Peltonen almost 12 years
    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?
  • Louis Kottmann
    Louis Kottmann over 11 years
    Instead of the 'tricky' (permissions & Permissions.Write) == Permissions.Write, you can now use enum.HasFlag()
  • Ed S.
    Ed S. over 11 years
    @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" :)
  • Louis Kottmann
    Louis Kottmann over 11 years
    @EdS. Hence the quotes ;) but admit that the first time it's not so obvious.
  • ArthurV
    ArthurV about 10 years
    @Nenotlep 32 positions of 1 in each position, yes, but the 33rd is all 0s, with 1 never appearing. ;-)