RawLib - fast roblox data types metamethod calls

RawLib

GitHub: here

Warning:

This module will most likely be patched as it is technically unintentional

Also this module is based upon this post


This is a module that collects most of the common Roblox metamethods in order to directly call them. You ask why? For optimization!

You might be thinking it provides a huge performance boost, but no. It fits between the ranges of microoptimizations as it is only intended for situations where the classic data type calls are the
performance bottleneck.


Example usage:

local RawLib = require("./RawLib")
local instance_index = RawLib.instance_index -- equivalent to local foo = script.Name (the dot operator)
local instance_newIndex = RawLib.instance_newIndex -- equivalent to script.Name = foo
local cframe_index = RawLib.cframe_index

print(instance_index(script,"Name")) -- prints the name of your script
instance_newIndex(script,"Name","asdas") -- sets the name of your script to asdas
local part = workspace:FindFirstChildOfClass("Part") or Instance.new("Part")
print(cframe_index(instance_index(part,"CFrame"),"LookVector")) -- prints 0,0,1 or the look vector of the found part

As you see, it makes code unreadable for the most part. So it is crucial to remember that you should only use it in cases where the standard operators create a massive bottleneck on your performance.

This module also includes *,-,/, and other such operators for their respective data types. Those work even better and provide even better optimization


Sounds fake?:

You can check this post to see the benchmarks of such raw calls. They only include raw instance indexing, but even that one is faster than standard dot indexing

Important info:

Please read this page to understand where to use the raw indexing and wherenot. Also, this does not work for methods. Please call them using the : as normal.

5 Likes

That’s going to be very useful for my upcoming module!
I would only use it for projects that are about to be made once and then forgotten, since updating them would be hell.
Also, it could be useful for math heavy operations involving CFrames and Vectors because if everything is stacked up, it will be a big difference, in my opinion.

I wanted to mention that the arithmetic operations on Vector3/vector are not metamethods and are actually built-in to the VM. The functions you’re getting through the hack is just the original closure.

It’s also better to index vector fields normally because it’s also a built-in operation, but it falls back to the slower metamethod when it errors.

1 Like

Thanks for the info. I thought it only for the vector library and not Vector3 I will update the github soon.

Edit it actually seems to only apply to Vector3

opened a PR if you’re interested

This is gonna be very useful!

As you can see here, $newindex is taking an ABSURDLY long amount of time for some reason:

Directly calling the function made a massive difference! Very nice

1 Like

It’s not unintentional, just undocumented. It will most likely NOT be patched.

I don’t understand why you say this. The code does not seem to be doing anything “wrong”, it’s not abusing any bugs in the Standard Library etc.


For anyone struggling to understand what the code is doing, let me break it down:

The first important detail is that, every time you try to access a property or function (more correctly a “member”) of a Roblox-created Object (returned by functions such as Instance.new or Vector2.new, A.K.A. a “userdata”), your Luau code is actually calling a specific function that returns a value.

This function is assigned to the __index field of the metatable of the Object you are interacting with, which you should be familiar with if you know OOP. The same applies for setting a value, which is done through the function Roblox assigns to __newindex.

The issue that this code tries to fix relates to how Luau figures out what the functions themselves are from their names, __index and __newindex. Using this code instead lets you call the functions directly instead of Luau having to find them each time, which is generally very fast anyway so you don’t usually have to worry about implementing this optimization.

Let’s take a simplified version of the code that’s easier to read. This version just finds the function acting as the __index for all Instances:

local Success, IndexFn = xpcall(
    function()
        return game.SomethingThatDoesNotExist
    end,
    function()
        local functionThatErrored = debug.info(2, "f")
        
        return functionThatErrored
    end
)

assert(not Success, "The first function should have thrown an error!")

print(`The name of the Workspace is: { IndexFn(workspace, "Name") }`)

So, what’s going on here?

  1. xpcall calls the first function, which tries to access game.SomethingThatDoesNotExist
  2. Luau, in order to figure out what the value of game.SomethingThatDoesNotExist is, must find the __index function of game, and call it with game and SomethingThatDoesNotExist as the arguments
  3. The __index function for Instances throws an error if there is neither a child Instance, nor a property of the Instance with the requested name, with the error X is not a valid member of Y 'Z'
  4. Because the function error’d, Luau calls the Handler that was given to xpcall within the stack frame of the __index function which threw the error
  5. The Handler uses debug.info, using a level of 2 to go to it’s parent stack frame, and asks for the value f, i.e. the function. Because the level is 2, this is the function that called the Handler, i.e. the function that error’d, i.e. the __index function
  6. We save the __index function to the variable IndexFn, allowing us to directly call it without Luau having to find it each time we want to use it
1 Like

o_O that seems like an important bug, it shouldn’t be that big of a difference on each individual assignment

It’s probably just my laptop lol, the problem is fixed so it doesn’t matter much anymore

1 Like

Using this or without using this?

Using this, another trick using xpcall() to retrieve the newindex function worked too