skip to content
Alvin Lucillo

Bitwise operations in const values in Go

/ 3 min read

💻 Tech

In Go, we can have ordered const values by using iota. For example, we can have a list of weekdays like so:

const (
    Sunday = iota
    Monday
    Tuesday
    Wednesday
    Thursday
    Friday
    Saturday
)

Sunday will have a value of 0, Monday will have a value of 1, and so on.

But you can also use bitwise operations in const values. This is specifically useful when you want to have a list of flags that you can use to check if a particular flag is set or not. For example, the excerpt below comes from log.go in standard library and uses the bitwise operator to set the flags:

const (
	Ldate         = 1 << iota
	Ltime 
	Lmicroseconds

The first const, Ldate, will have a value of 1 since the bitwise operator << shifts the binary representation of 1 (i.e., 0001) to the left by the iota (order of the const).

constiotashifting result
Ldate00001 << 0 = 0001 = 1
Ltime10001 << 1 = 0010 = 2
Lmicroseconds20001 << 2 = 0100 = 4

Why is this useful? Checking if the flag or combination of flags is set is as simple as using the bitwise operator & (AND). For example, the excerpt below from formatHeader function of log.go checks if the flag is one of the date, time, or microseconds flags, and if UTC flag is set, it converts the time to UTC

	if flag&(Ldate|Ltime|Lmicroseconds) != 0 {
		if flag&LUTC != 0 {
			t = t.UTC()
		}

Let’s set the flag first before any check happens. Suppose our main.go looks like this:

logger := log.New(os.Stderr, "ERROR", log.Ldate|log.Ltime)

Bitwise operator | (OR) is used to set the flag. The binary representation of log.Ldate is 0001, and the binary representation of log.Ltime is 0010. The bitwise operator | will set the flag to 0011 because the operator will set the bit to 1 if either of the bits is 1

0001
0010
----
0011 (i.e., 3)

Going back to the excerpt above that checks the flag, the bitwise operator & (AND) will check if the flag is set. The binary representation of log.Ldate is 0001, and the binary representation of log.Ltime is 0010. The bitwise operator & will check if the flag is set by checking if the bit is 1. If the bit is 1, it will return 1, otherwise, it will return 0. Suppose the flag value is 3:

In flag&(Ldate|Ltime|Lmicroseconds), bitwise OR operation on Ldate|Ltime|Lmicroseconds is represented by:

 0001
 0010
 0100
 ----
 0111 (i.e., 7)

In flag&(7), the bitwise AND operation is represented by:

 0011 (the flag value; i.e., 3)
 0111
 ----
 0011 (i.e., 3)

Since the resulting value is not 0, the flag is set.