Handling a lot of boolean fields

1,156 views
Skip to first unread message

Archos

unread,
Apr 21, 2012, 5:17:38 PM4/21/12
to golang-nuts
I've a struct with 15 boolean fields besides of another kind of
fields. Would be better if those boolean fields were managed like

type check uint16

const (
isFoo check = 1 << iota
isBar
...
)

although it it's most verbose during checking:

if check&isFoo != 0 {
...
}

Michael Jones

unread,
Apr 21, 2012, 5:23:55 PM4/21/12
to Archos, golang-nuts
It would be simpler to have a new type, "bit", that packs wonderfully
(8 to a byte ;-)

I know we don't have conversions so there would be no way to have a
bit take true or false, but at least you could assign 1 or 0.
--
Michael T. Jones | Chief Technology Advocate  | m...@google.com |  +1
650-335-5765

kortschak

unread,
Apr 21, 2012, 7:02:48 PM4/21/12
to golan...@googlegroups.com
It could conceivably take true or false as a constant (the same way as untyped consts can be assigned to floats or ints) and be convertable from bool (just as rune <-> byte for ASCII values or string<->[]byte) though. Not suggesting that this be done, but there is a way to get the sugar if you wanted it.

si guy

unread,
Apr 21, 2012, 7:50:01 PM4/21/12
to golan...@googlegroups.com
const (
FALSE iota
TRUE
)

Something about this makes me laugh

Ugorji Nwoke

unread,
Apr 21, 2012, 8:08:20 PM4/21/12
to golan...@googlegroups.com
IMO, If you're concerned about the size of the struct in memory, then having flags and checking bits may have some advantages (since a bool takes up one byte). From a user call site POV, I think having booleans is better. 

(I went through this just recently, having a uint holding flags, and finally changing to have multiple booleans because the API was not easier at the call site).

In my past life, we used BitSet in java where we wanted to keep a lot of bits together in one "object". It basically used a slice of longs to store bits, and had methods for setting and checking if some bits were set. The code is super simple to implement if you need it i.e. []byte, and given an offset, possibly expand []byte and set/check the appropriate bit in that byte.

OR do something super simple and custom like:
  type MyFlags [10]byte //supports up to 80 flags, etc. Change n up or down for more/less flags.
  func (MyFlag) IsSet(index i) //i <= 80
  func (MyFlag) Set(index i) //i <= 80

As with anything, use what best works for your code leveraging what the platform provides.

P.S. I haven't tried this ... but you get the idea.

Peter S

unread,
Apr 21, 2012, 8:17:06 PM4/21/12
to Ugorji Nwoke, golan...@googlegroups.com
You could (mis)use Int from math/bin in a manner similar to BitSet; it has Bit() and SetBit().

Michael Jones

unread,
Apr 21, 2012, 8:38:12 PM4/21/12
to Peter S, Ugorji Nwoke, golan...@googlegroups.com
If we had 'bit' then we would implicitly have arrays:

var flag [32]bit

would start with flag[0] .. flag[31] set to zero.

They would naturally pack into four bytes.

Peter S

unread,
Apr 21, 2012, 8:49:51 PM4/21/12
to Michael Jones, Ugorji Nwoke, golan...@googlegroups.com
That would indeed be very neat... The problem would be whether to allow bit-slices as well. Not allowing them would break the existing symmetry between arrays and slices, and allowing them would make the language more complex (probably unnecessarily, unless someone has good use cases for them which are not covered by Int in math/big).

Michael Jones

unread,
Apr 21, 2012, 9:26:08 PM4/21/12
to Peter S, Ugorji Nwoke, golan...@googlegroups.com
I know of no bit addressable computers, ever, other than the Intel
8051 which allows 16 bytes of bit addressable memory, and allows bit
access in registers, but that is a rare and slight exception to a
universal truth. Bytes are as good as it gets

Slices are easy once you deal with the real "problem" of bits and bit
arrays -- you cannot take the address of a bit using the same
monolithic pointer used elsewhere. Instead, such a sub minimum
addressable unit has a two component address, one of:

address of start byte : bit number (S:B) :
bit is ((*(S + B>>3)) >> (B & 0x7)) & 1

address of containing byte : bit number (S:B):
bit is (*(S) >> B) & 1

In full generality this is the size of a pointer plus 3 bits. (or more
bits if bigger chunks are used than bytes. You could allocate bit
objects in lower space (easily with 64 bits) and use the three
high-bits for bit-in-byte but that's starting to get complicated.

Once you decide on this, the slices work naturally.

minux

unread,
Apr 22, 2012, 1:16:15 AM4/22/12
to Michael Jones, Peter S, Ugorji Nwoke, golan...@googlegroups.com
On Sun, Apr 22, 2012 at 9:26 AM, Michael Jones <m...@google.com> wrote:
I know of no bit addressable computers, ever, other than the Intel
8051 which allows 16 bytes of bit addressable memory, and allows bit
access in registers, but that is a rare and slight exception to a
universal truth. Bytes are as good as it gets
In embedded computing, bit addressable register is pretty common.
In fact, ARM Cortex-M series even introduce a bit-band mapping for peripheral memory
space and internal ram space[1].
(each bit is mapped to a word in the corresponding bit-band region, so that bit flags are
easier to use without special compiler support)

Thomas Bushnell, BSG

unread,
Apr 22, 2012, 1:58:32 AM4/22/12
to Archos, golang-nuts

I would express it as clearly as possible...I.e., use booleans. Let the compiler pack it if it wishes; nothing prevents it.

Except in extremely rare cases, especially on modern computers, I would advise always erring on the side of clarity.

Thomas

Michael Jones

unread,
Apr 22, 2012, 5:08:01 AM4/22/12
to Thomas Bushnell, BSG, Archos, golang-nuts
Agree -- though like tail call optimization, having a contract with
the compiler would make all the difference to the developer.

--

Jan Mercl

unread,
Apr 22, 2012, 5:40:09 AM4/22/12
to golan...@googlegroups.com, Archos
On Sunday, April 22, 2012 7:58:32 AM UTC+2, Thomas Bushnell, BSG wrote:

I would express it as clearly as possible...I.e., use booleans. Let the compiler pack it if it wishes; nothing prevents it.

I would have thought that's not possible because of http://golang.org/ref/spec#Size_and_alignment_guarantees which are all >= 1. To my surprise, bool is not listed there (actually only numeric types are), so as long as the address is not taken, it seems bools can be in packed freely.

Graham Anderson

unread,
Apr 22, 2012, 4:03:41 AM4/22/12
to golan...@googlegroups.com
On Saturday 21 Apr 2012 22:58:32 Thomas Bushnell, BSG wrote:
> I would
> advise always erring on the side of clarity.

+1

Go spec + readable code is a very compelling reason to use this language in
the first place.
signature.asc

Jason Couture

unread,
Apr 22, 2012, 3:28:33 PM4/22/12
to golan...@googlegroups.com
Why not just make a bit field type?

type BitField struct {
       data uint16
}

func (b *BitField) Get(bitnum uint) bool {
       return ((b.data & uint16(1<<bitnum)) != 0)
}

//This is not how this function should be written, I just don't feel
much like thinking today.
func (b *BitField) Set(bitnum uint, value bool) {
       if value {
               b.data = b.data | uint16(1<<bitnum)
       } else {
               if b.Get(bitnum) {
                       b.data = b.data ^ uint16(1<<bitnum)

Hotei

unread,
Apr 22, 2012, 3:57:21 PM4/22/12
to golan...@googlegroups.com
If you're interested in a package that allows more than one words worth of bits you can check out my package at github:


I originally designed it for a "dirty buffer tracker" where I use it to track anywhere from hundreds to hundreds of thousands of dirty buffers that occasionally need "refreshing".  It looked useful so I extracted it to a package.  It has a test section and a benchmark section for those interested in same.

robin...@gmail.com

unread,
Jun 26, 2013, 6:49:43 AM6/26/13
to golan...@googlegroups.com
I know I am making a late entry to this discussion, but I dont see the problem with creating generic functions for the bitwise operations if you think they decrease readability. 


It works perfectly, is readable, and has good performance and memory footprint. The con is that it's not extendable to more than 64 flags per field, but it covers the most common use cases.
Reply all
Reply to author
Forward
0 new messages