Bitwise Flags are Beautiful, and Here’s Why | Hendrik Erz

Abstract: This is an article I've been wanting to write for a long time. Programming and writing code is often about efficiency: It has to work, and that's it. But there is more to code. Sometimes, it can be very beautiful, and there are a few patterns and capabilities of code that make it almost like art. Today I want to devote a full article to one such concept: Bitwise flags.


There is a feature in most modern programming languages that is very much under-appreciated today – or at least under-utilised: bitwise operations. Before the advent of modern high-level programming languages such as C, everything had to be written in Assembler code. Assembler is basically a language that can be used to tell your CPU quite literally what it should be doing. Instead of if and else-statements, you move bits around.

When higher-level programming languages (high-level because they allow you to understand better what your code will do, since they abstract more from what your CPU understands) were invented, nobody wanted to lose the ability to perform magic with bits. Plus, since everything has to be transformed into binary code at some point, every programming language can perform bitwise operations by definition. So today we have bitwise operations in every language – Rust, C++, Java, and even languages that don’t enjoy an image as robust such as JavaScript.

What are Bitwise Operations?

A bitwise operation differs from normal operations fundamentally. When you have, say, two numbers, and add them, you get the correct result. 2 + 2 = 4 except you’re Pippi Langstrumpf1. But obviously, your computer does not work like that. Your computer actually sees this: 00000010 + 00000010 = 00000100.

That’s two “2”s, but in their binary representation. Remember, binary works like this: You always have a byte of eight bits, each bit can be one or zero, and its decimal representation is multiples of 2. Below you can see one byte and which numbers the eight bits represent. Add all up and you end up with 256 numbers that can be contained (0–255).

0 0 0 0 0 0 0 0
| | | | | | | |
| | | | | | | +- 1   (2^0)
| | | | | | +--- 2   (2^1)
| | | | | +----- 4   (2^2)
| | | | +------- 8   (2^3)
| | | +--------- 16  (2^4)
| | +----------- 32  (2^5)
| +------------- 64  (2^6)
+--------------- 128 (2^7)

Your computer always performs bitwise operations. For example, calculating 2 + 2 works basically by adding up the bits (1 + 1 results in 10, so that is why the bit for four is set in position three and not two, as the two 2s).

There are many bitwise operations at your disposal: AND, OR, NOT, XOR are the most common. An AND-operation compares two bits and, if both are 1, you get a one. If one or both of the bits are 0, you get a zero. An OR-operation gives you back a 1 if at least one bit is 1. A NOT-operation works only on a single number and gives you the opposite of whatever you put in. Give the operation a 1 and you get a zero, give it a 0 and you get a one. The XOR (“exclusive or”) operation is tricky: It gives you back a one only if you put in one 1 and one 0, else it returns a zero.

There are more operations which are capable of, e.g., shifting bits back and forth, but we’ll only stick to the logical operations AND and OR for the remainder of this article, since that’s all you need for implementing bitwise flags. So bear with me!

Implementing a Bitwise Flag: An Example

Now that we’re all on the same page with regard to what bits and bytes are, let us take a look at bitwise operators. This works best if we have an example to work on. Let us assume you have the following function (I’m using TypeScript, because I can and because I’m a madman):

function printInformation (): void {
    const info: any = {
        firstName: 'Hendrik',
        lastName: 'Erz',
        affiliation: 'Linköping University',
        occupation: 'PhD Student'
    }

    console.log(`${info.firstName} ${info.lastName}, ${info.occupation} (${info.affiliation})`)
}

Next, let’s imagine you have a lot of data by users of some website (and not this hard-coded example), and you need to write a function that outputs pieces of information about a single user. Then there are some caveats you have to acknowledge.

For example, other users should only see the user’s first names, but never more private information which might be exploited by malicious actors. The page admins, on the other hand, should see every piece of information. Let us assume you have the task to write a function that only outputs certain pieces of information, and nothing more. And let us also assume you have no clue up front about who might want to see what kind of information.

What is the easiest way to do this? Certainly, the most trivial way would be to just write a new function for every piece of information that just logs a single piece of information, and then you tell anyone who needs it to simply call all the functions they need.

But that would be wasteful: Let us assume you always have to grab the user data from a database. If you have to display every piece of information, that could in our example result in four times retrieving the data, and only displaying 25% of the available information each time. Plus, that’s not DRY (“Don’t Repeat Yourself”), so it’s highly discouraged to do so.

Adding Flag Options

So how can we implement a function that works with very little code while still letting you meticulously control which information is displayed at every call? That’s where we can make use of a bitwise flag. First, we need to define which flags are available. We’ll use numbers for that and define a few constants in our code:

const FIRST_NAME = 1
const LAST_NAME = 2
const OCCUPATION = 4
const AFFILIATION = 8

You might already see a pattern here: I’ve deliberately used multiples of two, so that each of these constants has only one bit set: 00000001, 00000010, and so forth.

Implementing the Flags

Now let’s add that to our function:

function printInformation (which: number): void {
    const info: any = {
        firstName: 'Hendrik',
        lastName: 'Erz',
        occupation: 'PhD Student',
        affiliation: 'Linköping University'
    }

    if (which & FIRST_NAME) {
        console.log(info.firstName)
    }

    if (which & LAST_NAME) {
        console.log(info.lastName)
    }

    if (which & OCCUPATION) {
        console.log(info.occuption)
    }

    if (which & AFFILIATION) {
        console.log(info.affiliation)
    }
}

We can now call this function like this:

printInformation(FIRST_NAME | LAST_NAME)

printInformation(OCCUPATION | LAST_NAME)

What is happening here? You’re basically passing a number to the function which is the result of a bitwise OR. As you remember, an OR-operation gives you a 1 whenever one of the two bits is set to 1. FIRST_NAME | LAST_NAME thus result in a three (in bits: 00000011), since FIRST_NAME has its first bit set, and LAST_NAME has its second bit set.

Inside the function, we are now checking which of the bits is set by using a bitwise AND operation. The result is always one of two possibilities: Either you get a zero or the number of the flag you are checking for. This means, which & OCCUPATION will either return zero, if the third bit is not set in which (meaning that the caller did not want occupation to be logged), or four, since that’s the value of OCCUPATION.

Very strictly speaking, linters such as ESLint might at this point bark at you and complain that you can’t check a number in places where a Boolean comparison is necessary, and tell you that you must add an explicit check. In this case, what you could do is the following: which & AFFILIATION !== 0. This is equivalent to above, since 0 always evaluates to a Boolean false.

More Bitwise Magic

Sometimes, obviously, you want to execute additional steps in case a specific combination of options is given. For example, let’s imagine sometimes people only want to output a form of “shorthand” for a user in the form of “last name, occupation”.

This is also possible. You simply need to add two things: First a new constant that is the bitwise OR of LAST_NAME and OCCUPATION, and second an additional check in the function:

const SHORT_OCC = LAST_NAME | OCCUPATION

// ... snip ...

if (which & SHORT_OCC === SHORT_OCC) {
    console.log(`${info.lastName}, ${info.occupation}`)
    return
}

As you can see, here I’m checking explicitly against the value of SHORT_OCC. This means that the check is stricter now: The if-statement will only become true if only the last name and occupation flags are passed to the function. If any other flag is set, the condition will evaluate to false and nothing will happen. Furthermore, there is now an early return, since the conditions which & LAST_NAME and which & OCCUPATION would, in this case, also be executed, which we do not want (since then the info would be printed twice).

Conclusion: The Beautify of Bitwise Flags

Bitwise operations allow you to perform some very elegant checks. This way of using bitwise flags has many benefits. First, you can save a lot of typing, especially when you have a lot of options to turn on and off. Especially if you want to avoid too long function calls or passing a full object or dictionary (depending on the language) bitwise flags can be really handy. Also, they save a lot of memory. Not that your computer would run out of memory quickly, but it does speed up code execution considerably, something you will notice especially if you have functions that are being called ridiculously often. In that case, all your code has to actually do is to do a little bit of number magic, and since that’s built into every computer, your computer is really good at this.

Plus, even though I said “Well one byte has eight bits” you are not restricted to only eight options and their combinations. Normally, you work with numbers that have 64 bits, so you can expand your setting to 64 different settings! And I’m pretty positive that, if you run out of numbers, you really should refactor your code to use less options anyway. By the way, if you’re in languages with types, always make sure to use unsigned integers for that bitwise magic, since signed integers (i.e. numbers that can be negative) have to reserve the last bit for the sign (plus or minus) so that you effectively lose one option and have 63 remaining.

However, bitwise flags also have their shortcomings: They effectively act as switches, allowing you to turn something on or off. They are great at saving space and memory, but you cannot do anything except yes and no with these. So if you need parameters with other data types such as strings or numbers, you’ll still need to pass more parameters or even a parameter object. But just take a look at your code: Whenever you have several parameters that you pass to functions which effectively resemble “yes” or “no”, you can replace these with much more elegant bitwise flags. Or if your application has a lot of settings that are represented using check boxes. If there are at most 64 different check boxes in your code’s configuration, you can crunch them into exactly one single number.

And that’s the beauty of bitwise flags.


  1. Got this reference? Then feel free to chuckle a few seconds. 

Suggested Citation

Erz, Hendrik (2021). “Bitwise Flags are Beautiful, and Here’s Why”. hendrik-erz.de, 27 Jun 2021, https://www.hendrik-erz.de/post/bitwise-flags-are-beautiful-and-heres-why.

Ko-Fi Logo
Send a Tip on Ko-Fi

Did you enjoy this article? Leave a tip on Ko-Fi!

← Return to the post list