Bitwise vs Booleans for ON-OFF
Can someone tell me when it is more useful to hold ON/OFF states in a Long variable using an enum like this:
Enum UserStateEnum
eLoggedIn = 1
eWaiting = 2
eTalking = 4
eTransferring = 8
...
End Enum
Private meUserState as UserStateEnum
instead of a set of booleans like this:
Private mbUserLoggedIn As Boolean
Private mbUserWaiting As Boolean
Private mbUserTalking As Boolean
Private mbUserTransferring As Boolean
I understand that the single meUserState may take up less memory, but at the cost of always having to do this:
If (meUserState And eLoggedIn) Then
If (meUserState And eTalking) Then
...
instead of this (which I think is more readable):
If mbUserLoggedIn Then
If mbUserTalking Then
...
Is it just personal preference or is there a real reason to do bitwise stuff for this type of situation?
Wayne
Monday, January 12, 2004
I generally don't use a bitfield for a simple set of booleans.
Vastly the most common use for a bitfield, in my limited experience, is to pass a set of flags to a function in a single parameter, because that actually is easier and more convienent than, say, a parameter object, or 30 paramaters. But that's really the only example I can see off of the top of my head.
Mike Swieton
Monday, January 12, 2004
If you have a few then booleans are fine. When you
have 100,000s of them the bit fields can make
a big difference.
son of parnas
Monday, January 12, 2004
"I understand that the single meUserState may take up less memory, but at the cost of always having to do this:
If (meUserState And eLoggedIn) Then
If (meUserState And eTalking) Then
..."
I always define functions called BitSet and IsBitSet and then use that. Always looks better...
If (IsBitSet(eLoggedIn, meUserState)) Then...
Almost Anonymous
Monday, January 12, 2004
By the way, what language are you using? Is that Visual Basic?
It looks to me, from here, that there is no explicit difference between bitwise AND and logical AND?
I've really got to throw a vote for C and friends on this one. Unlike K ;) I really do find that the terseness of the bitwise and logical operations in C usually make things more readable (except for the XOR and NOT operations... ^ and ~? Who picked those?). Consider:
if (meUserState & (eLoggedIn | eTalking))
I think that's better than what we see above. Personal preference, I suppose, but then, I always did like bitfields :)
Mike Swieton
Monday, January 12, 2004
The breaking point may be lower than 100,00 because what about when you want to turn a bunch of them off at once?
With meState I can simply say "meState = 0" to turn off all flags. With seperate booleans, it can become a pain, especially when certain flags must be toggled in sets.
With meState I can do
meState =eLoggedIn + eTalking + eTransferring
but with seperate booleans I have to do
mbLoggedIn = True
mbTalking = True
mbTransferring = True
and then do the opposite for each during an inverse call to the logic. The sample application doesn't really apply, but think about 7 - 10 or so flags...
Wayne
Monday, January 12, 2004
Mainly I'm wondering about something like the original example, where you're tracking the state of something complex that can have many combinations of flags set at a given time.
I do have this in a module MBit.bas which makes bitwise operations stand out a "bit" more :)
Function FlagSet(Value As Long, Flag As Long) As Boolean
FlagSet = ((Value And Flag) <> 0)
End Function
I like using this technique for implementing a "Flags As Long/Enum" parameter in certain functions, because it's an easy way to extend the function without adding so many boolean params, like the VB MsgBox (+ it's nice with intellisense):
If MsgBox("Are you sure?", vbQuestion + vbYesNoCancel)
...
Wayne
Monday, January 12, 2004
Repeating what someone said earlier, bit flags are generally used as function parameters. foo(FLAG_LOGGED_IN | FLAG_TALKING) is more comprehensible than foo(true, false, true, false). With the latter format, nobody will remember what each Boolean argument means.
For local or member variables, I'll use separate Boolean variables, since they make the code more readable.
Julian
Monday, January 12, 2004
Bit operations are difficult in the rare few languages, it can save some space when sorting tables in memory if you have tons of fields that you can use binary fields to encode. Another thing people do that's falling out of favor (depends on the project: high performance or not, vldb or not) is to cheat on the int/longs, this saving is possible as long as you are SURE the number you are representating won't grow pass a certain number.
Li-fan Chen
Monday, January 12, 2004
Another common use is what JULIAN says, to the lay person it looks ridiculous at first glance to have setting1 OR setting1 to mean setting1 + setting2, but programmers have grown used to it.
Li-fan Chen
Monday, January 12, 2004
Go with single state variables. Multiple state variables will get out of sync (been there done that)
It makes your code more maintainable. Suppose that part of your state is what's being edited at the moment, which controls which menu options are valid.
If you have some variables called things like:
IsText, IsNumber, IsPicture and InEdit
Then in theory you should never have any of IsXXX variables set at the same time as InEdit. In practice someone will screw this up. It's nearly always easier to have code which reads
CurrentState=IsPicture or InEdit
to go into picture editing mode rather than having to remember the 4 or 5 booleans that then need clearing or setting (Please note this example is slightly contrived).
Peter Ibbotson
Monday, January 12, 2004
Another situation where overlapped state values are used is when combinations are frequently used.
i.e.
Enum UserStateEnum
eLoggedIn = 1
eWaiting = 2
eTalking = 4
eLoggedInTalking = 5
eTransferring = 8
...
if (meUserState and eLoggedInTalking) Then...
Obviously any number are possible. While each state is still an individual boolean value, they can be set in bulk (as others mentioned about being about to 0 it all out) or compared in bulk in one step.
Dennis Forbes
Monday, January 12, 2004
I don't recall having seen bit fields used in a local variable.
They're useful in a parameter (or in a struct that's used in an API). If you take an API function such as CreateWindow, in a subsequent version of the function a new feature can be added by defining a new (previously unused) bit in the "dwStyle" parameter, without needing to recompile existing clients. Whereas, if the new boolean were defined as a new parameter (instead of as a new bit field in an existing parameter), then the function signature would have changed (resulting in something like CreateWindowEx).
Christopher Wells
Monday, January 12, 2004
Enums are cool you have more states than the boolean two allows for, e.g. :
enum {
eLoggedIn,
eWaiting,
eTalking,
eTransferring
} iState;
Using an enum to encode bitwise flags is an *entirely* different thing. In Pascal, there was even different syntax to emphasise this.
Using your state enum as bitwise flags means that you can be both eTalking and eTransferring, for example. Does that make sense to you?
Things like 'logged in' are usually boolean: either you are or you aren't. Things like 'wait, talking and transfering' are usually exclusive too.
At the risk of reading too much of my context into your choice of example code, I'd warn that maybe bitwise flags aren't what is required in this instance at all..
i like i, outspoken
Monday, January 12, 2004
> It looks to me, from here, that there is no explicit difference between bitwise AND and logical AND?
There is no logical AND operator in VB "Classic". The AND operator in VB Classic is bitwise. That's why True in VB is actually the constant -1, which has binary image 0xFFFFFFFF.
This leads to a number of potential gotchas, like:
Foo = 1
Bar = 2
If Foo And Bar Then ...
if you come from a C background and read that as (Foo && Bar), you've just parsed it wrong.
Since those are not logical, VB Classic doesn't have lazy operators. For example:
If (Not Foo.Bar Is Nothing) And (Foo.Bar.Blah > 2) Then ...
will die horribly because both sides are evaluated even when the left side is false.
In VB.NET there are new logical operators AndAlso and OrElse which do implement lazy logic:
If (Not Foo.Bar Is Nothing) AndAlso ...
Eric Lippert
Monday, January 12, 2004
Having spent the last 2 years maintaining an ASP/VB app initially written by a developer who just LOVED the fact that he understood how bitwise flags worked, I have to chime in here and say it is pure masturbation.
Bitwise flags are only acceptable if there is some API call you need that requires them. Even then their use should be hidden from general view inside a wrapper.
Claiming that you find the code using bitwise flags to be more readable might as well be the developer equivalent of "Hello, my name is Neil, and I am an alcoholic"; You need help.
Neil
Monday, January 12, 2004
As far as long-term maintainability goes, bitfields leave something to be desired. They're great for minimizing memory usage, but when the number of options you need to track flows beyond the capacity of a long, it's tough meadow muffins for you.
Not catching this recently cost me a couple of days on a fixed-price project. I had inherited the code from three successive programmers, all of whom used bit flags to track program options. Not really being aware of how many options there were, I gleefully added some new ones. Then execution started to get a little funky. So I lost another three days recoding the options into a more easily extensible object, since over the life of this project it's likely to get even more options.
In this case, encoding it as this "enormous" object actually shank the compiled size and the code size, as well an enhancing readability. This won't always be the case, but the old way of using bitfields made for a lot of redundancy in the code that I was able to take out.
Clay Dowling
Monday, January 12, 2004
It doesn't matter.
There are far weightier issues for determining code quality.
Good code could use either.
Ch 10
Monday, January 12, 2004
"Bitwise flags are only acceptable if there is some API call you need that requires them. Even then their use should be hidden from general view inside a wrapper."
The best use of bitwise flags are in function parameters. Using booleans for this purpose generally leads to unreadable and just-plain-ugly code.
Saw I start with a function with a single boolean parameter:
Print(Bool showHeader);
The showHeader was added as boolean because that was the only option that was needed. Many years go by and more flexibility is needed:
Print(Bool showHeader, Bool showFooter = false);
All is good. The code is backwards compatible with anything that calls it. But the calls are getting uglier. Then more flexibility is needed:
Print(Bool showHeader, Bool showFooter = false, Bool showColumnHeader = true, Bool showPageNumbers = true);
Again, backwards compatible but getting uglier...
Print(true, false, true, false);
Who the heck knows what that does!
Boolean flags allow flag-controlled functions to be more extendable and readable at the same time:
Print(P_SHOWHEADER | P_SHOWCOLUMNHEADER);
But bit fields are still pretty ugly! The bit fields are used to represent a Set. The implementation would be so much cleaner in a language that natively supports a Set data type and has the appropriate operators.
Almost Anonymous
Monday, January 12, 2004
Bit fields make sense in C but not in most other languages.
For example, I'm not aware of any bit field parameters in the JDK. In Java, it's much more common to store parameters in a hash table.
In C, you wouldn't want to create an unnecessary data structure like that, since you'd have to worry about who's responsible for freeing the memory.
People using bit fields in Java or VB are probably former C coders.
Julian
Monday, January 12, 2004
Call me a nitpicker, there actually are bit fields in the JDK interface methods (e.g. java.awt.image.imageobserver). It looks like they are following the general rule of 'bitfields only for method parameters' .
Yves
Tuesday, January 13, 2004
Saving memory is the last of the reasons to use bit fields. They are a useful paradigm and they have their rightful place in programming. One of the best examples coming to my mind is the file attributes. How will you better express a file having these properties: Read/Write/Shared/Hidden/System? Would you create N booleans for N properties?
Bit fields are well supported in .Net as well, just don’t forget to use the [Flags] attribute on your enum.
coresi
Tuesday, January 13, 2004
I should clarify that even though I was very irked by bitfields on one particular project, I do generally like them for a lot of other things. They're just kind of stinky when long term persistence is needed, the number of options can be very large, and the same set of options get used in many places in the code.
Clay Dowling
Tuesday, January 13, 2004
It seems that the project Chris Dowling was working on did not define all the bitmap values in one place. Eeww!
njkayaker
Tuesday, January 13, 2004
This thread just screams "state machine." NFAs are handy once you get beyond 2 or 3 booleans.
Jason McCullough
Tuesday, January 13, 2004
Recent Topics
Fog Creek Home
|