Bitwise operations made easy with Haxe
— Haxe
This blogpost is about making bitwise operations in Haxe more easy. If you like doing micro optimization in your code, you probably want to use bitwise operations. But I found the main problem about bitwise operations is that they are hard to read. If you know the syntax and know what it does it might be “doable”, but if you work in a team it might get harder if not everyone is familiar with the syntax.
A common example of using bitwise operators is to put multiple states into one integer. Some call them flags.
For example, lets say you want to build a app where users have different rights to view a document. You could create a User class with multiple booleans like this:
class User {
public var name:String;
// user rights
public var CAN_VIEW:Bool = true;
public var CAN_ACCESS:Bool = true;
public var CAN_EDIT:Bool = false;
public var CAN_GRANT_ACCESS:Bool = false;
public var CAN_REVOKE_ACCESS:Bool = false;
public var CAN_DELETE:Bool = true;
}
But if you want to optimize it, you could also put all those values into an variable. Computers deal with ones and zeros right?
class User {
public var name:String;
// user rights
public var rights:String = "000001";
}
In this case we create a string with zeros and ones. We could say that the last value means “can view” and the one next to it “can access” etc.. In our case only the last digit is “1” so that means it is on (true). the others are “0” so they are false.
Understanding bitwise operations
Well, this could work, but working with numbers in strings is not very elegant, and also not practical. And it’s awkward when you want to add another flag to it. Why don’t we just use a number for that? That’s where bitwise operations come in. Let’s put it in an integer:
class User {
public var name:String;
// user rights
public var rights:Int = 0;
}
Given the last explanations,
we can say:
CAN_VIEW == 000001
CAN_ACCESS == 000010
That would mean that:
CAN_ACCESS and CAN_VIEW == 000011
When we translate it to code it would be:
1 | 2 == 3

For those who can count binary, 000011
in real value equals 3. By the way, the leading zero’s don’t mean anything.
Ok, let’s move on and define all our flags. Define a new class that has all the access flags in it like this:
class Access {
public static inline var CAN_VIEW:Int = 1;
public static inline var CAN_ACCESS:Int = 2;
public static inline var CAN_EDIT:Int = 4;
public static inline var CAN_GRANT_ACCESS:Int = 8;
public static inline var CAN_REVOKE_ACCESS:Int = 16;
public static inline var CAN_DELETE:Int = 32;
}
As you see the order is: 1, 2, 4, 8, 16, 32 (and if we go further 64, 128, 256, 512 etc etc..)
This means when 1 | 2 == 3
, we can now do:
var user = new User();
user.rights = Access.CAN_VIEW | Access.CAN_ACCESS;
trace(user.rights); // 3
Play with this live-example to see how you can blend different flags.
Nice! now we know how to mix and blend different rights to the user. Let’s say you want to make somebody admin you can do this:
user.rights = Access.CAN_VIEW | Access.CAN_ACCESS | Access.CAN_EDIT | Access.CAN_GRANT_ACCESS | Access.CAN_REVOKE_ACCESS | Access.CAN_DELETE;
To go back on how we declared the Access class, I think it can be improved. It now has that count that is slightly annoying since it doesn’t feel natural. Let’s look at this table.
Real value | Binary | Left shifted |
---|---|---|
1 | 000001 | 1 << 0 |
2 | 000010 | 1 << 1 |
4 | 000100 | 1 << 2 |
8 | 001000 | 1 << 3 |
16 | 010000 | 1 << 4 |
32 | 100000 | 1 << 5 |
As you notice in the last column, the same values can be achieved with a left shift <<. So “000001” equals “1” but is the same when we write it like “1 << 0”. Personally I think its more readable to have this last column in your code because it just increases normally, what do you think?
Nicer syntax with Haxe enum abstract
Let’s use the power of Haxe to simplify the Access class. Instead of using static vars, let’s create an enum abstract.
enum abstract Access(Int) from Int to Int {
var CAN_VIEW = 1;
var CAN_ACCESS = 2;
var CAN_EDIT = 4;
var CAN_GRANT_ACCESS = 8;
var CAN_REVOKE_ACCESS = 16;
var CAN_DELETE = 32;
}
But wait, let’s also use the left shift so we don’t have to count those 1,2,4,8 etc..
enum abstract Access(Int) from Int to Int {
var CAN_VIEW = 1 << 0;
var CAN_ACCESS = 1 << 1;
var CAN_EDIT = 1 << 2;
var CAN_GRANT_ACCESS = 1 << 3;
var CAN_REVOKE_ACCESS = 1 << 4;
var CAN_DELETE = 1 << 5;
}
That looks a bit friendlier because if you now want to add another field, you can just add “1 << 6
” and “1 << 7
“. But hey this post was about readability right? Why not create a simple function so we can get rid of this “1 <<
” thingy? Yep, we can! 😀
enum abstract Access(Int) from Int to Int {
var CAN_VIEW = value(0);
var CAN_ACCESS = value(1);
var CAN_EDIT = value(2);
var CAN_GRANT_ACCESS = value(3);
var CAN_REVOKE_ACCESS = value(4);
var CAN_DELETE = value(5);
static inline function value(index:Int) return 1 << index;
}
Ah, in my opinion everybody can maintain this. Even if you don’t understand what’s happening. Since we use the ‘inline’ there is no actual function call in the output. You can see in this live-example how the generated output looks like. Neat! Now, that’s it for the Access class.
We created an actual type!
Hey! Since Access is now an actual type, we can even define user.right
as follows:
public var rights:Access; // isn't this nice!?
But it still translates and actually works as an integer when it is compiled.
Working with bitsets in Haxe
Let’s go back to the user.rights field. What if we want to remove a flag? The syntax for that would be:
user.rights = user.rights & ~Access.CAN_EDIT;
😯 Aiiii, there goes our readability isn’t it?
Well lets create a utility class that contains a remove function. I use this BitSets class from Flambe, which has some other nice functions too (like testing if a integer contains a flag).
class BitSets {
inline public static function remove (bits:Int, mask:Int):Int {
return bits & ~mask;
}
inline public static function add(bits:Int, mask:Int):Int {
return bits | mask;
}
inline public static function contains (bits :Int, mask :Int) :Bool {
return bits & mask != 0;
}
}
With the above, we can now use this much more readable code:
// add flags
user.rights = user.rights.add(Access.CAN_EDIT).add(Access.CAN_ACCESS);
// remove flags
user.rights = user.rights.remove(Access.CAN_EDIT);
// check if flag exist
if (user.rights.contains(Access.CAN_ACCESS)) {
trace("can access");
}
With Haxe, you could also leave out the enum class (if it’s imported or a class inside your module), so we can write:
// add flags
user.rights = user.rights.add(CAN_EDIT).add(CAN_ACCESS);
// remove flags
user.rights = user.rights.remove(CAN_EDIT);
// check if flag exist
if (user.rights.contains(CAN_ACCESS)) {
trace("can access");
}
It doesn’t get cleaner than that.
Check out this full live-example to see how it all comes together and what the effect is on the generated output.
Conclusion
- We saved ourselves from multiple booleans on a user class, we’ve learned how to use flags.
- We made a enum abstract type called Access for our user.rights property.
- Working with bitwise operators can be readable.
- This BitSets class is very nice to have.
- The functions created to make this readability happen does not affect the output thanks to inlining.
- You can use this technique for quite some classes. I think when you see classes with multiple booleans, you could consider using flags.
Actually, it CAN get even cleaner if you specify your utility methods right in the Access abstract, so you don’t even need static extension.
Like this: http://try.haxe.org/#79c4F
Also, one may wont to hide the Int nature of that abstract completely and only work with ints within the abstract code (so remove from/to Int and use cast or private converting helpers: http://try.haxe.org/#9838C)
Thanks nadako, those are great additions!
Very nice article! Thanks 😀
there is a tiny problem, bit masks are limited by the underlying Int storage, in this case, that would be until 2^31, or 2^63. or if uint, one more.
(it means the values that it can store are limited to 63)
Another way to do it is to use a Set (a unique list) and just add/remove those enum values.
The value of that is that the code is clear, and since this is not compiled to run on a lowly calculator, but on an actual computer, the speed is mighty enough.
maybe when computers are this fast, we can remove the fixation on bitmasks 🙂
very nice and educating post, thank you!
I think this std lib utility deserves a mention: http://api.haxe.org/haxe/EnumFlags.html 😉