Interminable Interminable - 5 months ago 27
Vb.net Question

Bitwise operations - checking and removal

Note the simple example below:

Module Module1
<Flags>
Public Enum Names
None = 0
Test = 1
Test2 = 2
Test3 = 4
Test4 = 8
End Enum

Sub Main()
Dim test As Names = Names.Test Or Names.Test3
If (test And Names.Test3) = Names.Test3
Console.WriteLine("TRUE")
Else
Console.WriteLine("FALSE")
End If
End Sub
End Module


The first part of my question relates to the line
If (test And Names.Test3) = Names.Test3
.

Wouldn't it be better to simply check
If test And Names.Test3
as if the flag exists? If it evaluates to a non-zero value (meaning the flag exists) then the result of the condition would be
True
anyway.

Is there a good reason to use the first way of checking over the second? (Whilst my answer is for VB.NET, I would also be interested in knowing if this is a potential pitfall anywhere else, ie C#, C++, etc).

Also, with regards to flag removal, it seems there's two ways to do this:

test = test Xor Names.Test3
and
test = test And Not Names.Test3


However, the first will add the flag if it's missing, and remove it if it is there, whereas the second will only remove it. Is that the only difference? Or is there another reason why I should prefer one method over the other?

Answer

You are correct in stating that you can effectively replace this:

If (test And Names.Test3) = Names.Test3 Then

with this

If (test And Names.Test3) Then

But, the second example will not compile with Option Strict On as you rightly get the error:

Option Strict On disallows implicit conversions from 'Names' to 'Boolean' so in order to get this to compile you need to wrap a CBool round it.

So, in conclusion I would say it is much better to use the first example as the intent is very clear:- you are checking to see if a bit is set.

In terms of flag removal i.e. unsetting a bit you should use:

test = test And Not Names.Test3

Using Xor has the effect of toggling the value.

The following might help (especially if you make them extension methods):

Public Function SetBit(ByVal aValue As Names, ByVal aBit As Names) As Names
    Return (aValue Or aBit)
End Function

Public Function ClearBit(ByVal aValue As Names, ByVal aBit As Names) As Names
    Return (aValue And Not aBit)
End Function

Public Function IsBitSet(ByVal aValue As Names, ByVal aBit As Names) As Boolean
    Return ((aValue And aBit) = aBit)
End Function

Public Function ToggleBit(ByVal aValue As Names, ByVal aBit As Names) As Names
    Return (aValue Xor aBit)
End Function