Please add bitwise operators (<<, >>, ~, & and |)

As a Roblox developer, it is currently difficult to make expressions that utilise chains of bitwise operators look clean.

The reasoning is because to do any bitwise operation, we need to defer to the bit32 library, rather than being able to use mathmatical equations.

Lets take a simple algorithm, decoding a ULEB128 number from a binary stream, in most high level languages, we can use the operators for bitwise AND and bitwise shifting to create this nice, clean and readable algorithm.

const decodeSignedLeb128 = (input) => {
  let result = 0;
  let shift = 0;
  while (true) {
    const byte = input.shift();
    result |= (byte & 0x7f) << shift;
    shift += 7;
    if ((0x80 & byte) === 0) {
      if (shift < 32 && (byte & 0x40) !== 0) {
        return result | (~0 << shift);
      }
      return result;
    }
  }
};

But in Luau, we need to make calls to the bit32 library, which results in this much noisier function:

local function decodeSignedLeb128(b: buffer, offset: number): number
  local result, shift = 0, 0
  while true do
    local byte = buffer.readu8(b, offset)
    result = bit32.bor(result, bit32.lshift(bit32.band(byte, 0x7F), shift))
 
    shift += 7
    offset += 1
    if bit32.band(byte, 0x80) == 0 then
      if shift < 32 and bit32.band(byte, 0x40) ~= 0 then
        return bit32.bor(result, bit32.lshift(bit32.bnot(0), shift))
      end
      return result
    end
  end
end

there may be logic errors here, using this as an example

As you can see, especially with result, we had to chain a massive statement of bit32 calls, to do something that is a lot cleaner with operators.

I’m also requesting this because it would aid in porting file parsers from other languages that run under the assumption that bitwise operators exist, and its less hassle to unwind the order of operations if I can create a 1:1 mapping with equivalent operators.

If Roblox were to address this issue it would improve my development experience because it would result in cleaner code when working with bitwise operators, and make it easier to port code from other languages.

14 Likes

Roblox can already differentiate if usage of e.g the [] computed index operator, {} table constructor, “” string constructor, etc is done in runtime or inside types, adding bitwise operators would 100% be a non-issue to implement (even though alot of type operators are bitwise operators)

I however don’t support removal of the bit32 library, both for backwards compatibility and also because bit32 has useful functions like countlz, countrz, btest, extract, etc which aren’t able to be made into operators

It’s similar to math.pow vs ^, most people don’t use the first one but it’s there anyway

3 Likes

One of the main issues that gets mentioned in the reasoning for it not being added is metamehods, first of all, __idiv and __iter, but really, I dont care about metamethod support for them, its a nice features yes, but I just want readable code on complex expressions.

Another part is saying that ^ isn’t available for XOR and is inconsistent with other languages: != all over again.

I would happily take the bitwise operators getting compiled down to FASTCALLs to the bit32 library, similar to how string interp is actually string.format in disguise

3 Likes

Yeah it’s a shame we can’t get xor, I also wouldn’t want metamethods for bitwise (C++ slop all over again :V)

Alot of my more complex bit manipulation code would for sure look alot cleaner too

Lua 5.3 uses ~ for XOR. As far as I’m aware, except for ~=, the tilde is not used anywhere else in the language.

3 Likes

I just don’t see the point in making everyone use different operators and making people have to adapt, change their mindset and change all the operators in their games to these ones?

1 Like

You don’t have to change your bit32 function calls to this one; ideally bit32 would stay (as it does contain functions operators can’t do), the operators would simply make code which manipulates bits

  1. More readable
  2. More easily rationalized (using bit32, operations go right to left which is extremely unintuitive :frowning: )
1 Like

This would not change any existing language semantics, you can use bit32 if this change was added the same way you would now.

You could still use pairs and ipairs when generalised iteration got added, you could still wait (you shouldn’t) when task.wait got added, and you can still use coroutine when the task library as a whole got added, this would be no different.

1 Like

Honestly, I’d love this. While the bit32 library functions have been a great alternative to standard bitwise operations it still isn’t quite as intuitive if you are used to these operations coming from a language other than Lua. I think a big advantage Luau can have over standard Lua is additions that directly ease switching over from other languages and workflows.

2 Likes

This was already decided against when the team adopted the new syntax for generic function calls:

local foo = React.useState<<number?>>(nil)

So I don’t think this is on the table anymore.

4 Likes

They’ve also made their stance against it clear on the compatibility page regarding lua 5.3.

It’s important to highlight integer support and bitwise operators. For Luau, it’s rare that a full 64-bit integer type is necessary - double-precision types support integers up to 2^53 (in Lua which is used in embedded space, integers may be more appealing in environments without a native 64-bit FPU). However, there’s a lot of value in having a single number type, both from performance perspective and for consistency. Notably, Lua doesn’t handle integer overflow properly, so using integers also carries compatibility implications.

If integers are taken out of the equation, bitwise operators make less sense, as integers aren’t a first class feature; additionally, bit32 library is more fully featured (includes commonly used operations such as rotates and arithmetic shift; bit extraction/replacement is also more readable). Adding operators along with metamethods for all of them increases complexity, which means this feature isn’t worth it on the balance. Common arguments for this include a more familiar syntax, which, while true, gets more nuanced as ^ isn’t available as a xor operator, and arithmetic right shift isn’t expressible without yet another operator, and performance, which in Luau is substantially better than in Lua because bit32 library uses VM builtins instead of expensive function calls.

2 Likes

We have received feature requests for this before, but we have decided against having bitwise operators in Luau.

Reasons include those listed above from the Luau Compatibility section as well as ambiguous parsing of <</>> with explicit generic function parameters and a negative impact on performance in presence of metamethods.

12 Likes