4

While learning the flag technique, I encountered some problem, hereby I'm showing this example using C#, with Enum:

   [Flags]
    enum PermissionTypes : byte
    {
        None = 0x0,
        Read = 0x1,
        Write = 0x2,
        Modify = 0x4,
        Delete = 0x8,
        Create = 0x10,
        All = Read | Write | Modify | Delete | Create
    }

To check hasFlag property:

if((value & mask) == mask) {...}

But when 'hasFlag' applied on both 'None' and 'Read':

Denote x = Current_Permission_Setting,

x & PermissionTypes.None = always false
x & PermissionTypes.Read = always true IFF 

(cont') IFF x = {ODD byte value}


Question: What are the perfect sets of flag values that are safe to be used?


Reference: Here's the full example.

Roy Lee
  • 10,572
  • 13
  • 60
  • 84
  • I think you should cast it to enum for doing the bitwise operation in this case – Dan Hunex Jan 17 '13 at 16:38
  • 2
    In your example, None isn't really a flag value (you can't check it with the logic you have). The 'problem' you see for 1 is just the definition of the 1 bit in binary arithmetic. – antlersoft Jan 17 '13 at 16:38
  • For C#, see [System.FlagsAttribute](http://msdn.microsoft.com/en-us/library/system.flagsattribute(v=vs.100).aspx). – Austin Salonen Jan 17 '13 at 16:40
  • 1
    `IFF x contains any ODD byte values`: Well, of course it does. If the value is odd, the first bit will be set, so the read bit (as per your definition) is set. If you want to know if *only* the read bit is set, just compare your value to `PermissionTypes.Read`. If you want to know if the read bit is set, regardless of what other bits are set, use the `& mask = mask` trick. – Matt Burland Jan 17 '13 at 16:44
  • @antlersoft Mind enlighten me with a solid example on 'flag value'? – Roy Lee Jan 17 '13 at 16:44
  • http://stackoverflow.com/q/93744/10396 may help. – AShelly Jan 17 '13 at 16:49
  • @MattBurland What if I'm allowed to check the read bit is set, regardless of what other bit are set. Does that mean I couldn't use ODD value as flag ? – Roy Lee Jan 17 '13 at 16:59
  • 1
    @Roylee: Your flag values should be powers of 2. I.e. 1,2,4,8,16,32,... any other values will be combinations of those flags. For example, you could create a `ReadAndWrite` flag with a value of 3, but that would be a combination of the `Read` and `Write` flags. – Matt Burland Jan 17 '13 at 17:04
  • The way you are using 'All' in the enum is probably not right. Each value of the enum you use should be a valid power of two. In the case of 'All', it is 31. – gprasant Jan 17 '13 at 17:19

2 Answers2

6

As @antlersoft says in the comments, you can't really use NONE as a bitflag.
The rest of your flags make sense. You do need to use the powers of 2 to get 1 bit per flag.

It doesn't make sense to test for "Has READ and NONE" set, anyway, since NONE implies READ is not set.

The problem you describe with odd values of X doesn't seem to make sense. The value will only be odd if bit 1 is set. If you are using your flags consistently, bit 1 will only be set if READ is true.

AShelly
  • 34,686
  • 15
  • 91
  • 152
  • Yes, `None` (or any enum value of `0`) is not a flag, it is the absence of any flags. – Olivier Jacot-Descombes Jan 17 '13 at 16:50
  • @OlivierJacot-Descombes ok, noted! I would exclude 0 from flag values set then. :) – Roy Lee Jan 17 '13 at 16:54
  • So according to what you said, I got to make sure that all my flags are 'EVEN', or 'powers of 2'? – Roy Lee Jan 17 '13 at 17:02
  • 2
    @Roylee: It is a good practice to have `None` with the value `0` in an enum, in order to be able to clear a variable: `permission = PermissionTypes.None;`. The point is that you cannot test it like a flag. Just test `permission == PermissionTypes.None`. And flag values have always the values 1, 2, 4, 8, 16, 32 ... These are powers of two (2^0 = 1, 2^1 = 2, 2^2 = 4 ...). It has nothing to do with even and odd. – Olivier Jacot-Descombes Jan 17 '13 at 17:04
  • In this case, can you explain how I would denote 'None' permission if it is not right to have it as a bit flag? – gprasant Jan 17 '13 at 17:10
  • 1
    @gprasant: There is no `None` permission. If no permission is given then no flag has to be set at all! Just set `permission = PermissionTypes.None;`. This clears all the flags and thus all the permissions. "None" means "not any permission" here. – Olivier Jacot-Descombes Jan 17 '13 at 17:24
  • 1
    exactly. None means "not any of the others". You can't test `hasFlag(None)` using the code above. For none, the test is simply `(value == None)`. – AShelly Jan 17 '13 at 17:30
  • got it. In this case, the value '0' has to be treated different from the other flags. When checking for what permission a user has, I'd check if permission == permission.None and only if this is false, Id proceed to see what flags are set – gprasant Jan 17 '13 at 17:32
1

x & PermissionTypes.Read checks if last bit of the value x is set which by itself means nothing as you've found. Programer can interpret it in several ways:

  • x has Read flag set via x = Read or x = x | Read.
  • x is odd (or more precisely gives remainder 1 when divided by 2^1), similar to x & 3 - reminder when divided by 2^2.

Flags representing individual bit values are commonly used as in sample you've shown. It is up to programer to decide what meaning is to assign to each flag.

One more sample of flag usage - check if passed in integer is negative by checking "sign" bit:

[Flags]
enum StrangeFlags : uint {
    Negative = 0x80000000,
}

int x = -1;
var isNegative = ((StrangeFlags)x & StrangeFlags.Negative) != 0
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179