Global Metatable Functions

Raw functions and newproxy.

by GR1PP3RTV

Author Avatar

Warning: Before viewing the tutorial, you need to understand about metatables The functions in this tutorial are Lua Globals, so you can use it on any engine that uses lua. If any code or information is wrong, please send me feedback.

Functions Introduction

Global metatable functions are functions outside of metatable, these functions can change the table without metatatble interrupting. newproxy is a different function that can be used to create resources in the code environment.

Functions:

<userdata> newproxy(bool addMetatable = false)

Creates a new userdata, using metatable.

<variant> rawequal(v1, v2)

Checks if v1 equals v2, without invoking __eq metamethod.

<variant> rawget(array table, index)

Gets the value of index from real table, without invoking __index metamethod.

table rawset(array table, index, value)

Sets the real value of real table index, without invoking __newindex metamethod (can be used against the ReadOnly method).

If you don't understand, will have some examples below, the examples are well explained for a better understanding.

Functions Examples

First let's make a metatable for the examples, named "Met".

local Met = setmetatable({JohnDoe = 1, ROBLOX = 2, Admin = 3}, {
    __index = function() -- For rawget
        error("Not is possible to call a index")
    end,

    __newindex = function() -- For rawset
        error("Not is possible to create a new index")
    end,

    __eq = function() -- For rawequal
        error("Not is possible to compare the table")
    end
})

Ok, now you think, how will I call some index or create and compare the table if it is not possible? Well, so that's why there are these raw functions, to set the table without calling these metamethods.

First, let's call some index by the rawget function, without invoking the __index metamethod.

print(rawget(Met, "JohnDoe")) -- 1
-- Good, now let's see if we can get the index value without using rawget

print(Met.JohnDoe) -- Error: Not is possible to call a index
-- Oh, can't call an index without rawget

The error that occurred was because invoking the __index metamethod, but with rawget doesn't invoke this metamethod. To you understand better, if you use rawget on any table with a metatable, it will not invoke this metatable's __index metamethod, so the __index metamethod function will not be executed.

Now let's create an index on the table, without invoking the __newindex metamethod.

rawset(Met, "GR1PP3RTV", 4)
-- Not give error

-- Let's try calling the index without rawget
print(Met.GR1PP3RTV) -- Error: Not is possible to call a index

-- With rawget
print(rawget(Met, "GR1PP3RTV")) -- 4

You can see that when creating a new index with rawset, it will not give error, like rawget, but without, it would give the error, because it would invoke the __newindex metamethod. Other example:

rawset(Met, "Pizza", 5)
print(Met.Pizza) -- Error: Not is possible to call a index
print(rawget(Met, "Pizza")) -- 5

The same, so rawset would be just like rawget, but it creates instead of getting. Now the last function, rawequal, same as rawset and rawget, but without invoking the __eq metamethod.

print(type(Met) == "table") -- Error: Not is possible to compare the table
print(rawequal(type(Met), "table")) -- true
print(Met == Met) -- Error: Not is possible to compare the table
print(rawequal(Met, Met)) -- true

As you can see, an equal operator can invoke the __eq metamethod, rawequal is different, it does not invoke the metamethod, just like the other functions. It is very easy to understand, if you did not understand, read again.

Now finnaly let's go to newproxy, this function is not used for metatable. The function creates a new userdata, the same as creating a Roblox Service with a metatable setting.

Let's create a new lua global with newproxy.

local toString = setmetatable(newproxy(true), {
    __newindex = function()
        error("toString is read-only")
    end,

    __call = function(table, ...)
        local arguments = {...}
        local string = arguments[1]
        arguments[1] = nil

        return tostring(arguments[1], unpack(arguments))
    end
})
-- Created a new lua global called "toString", replacing tostring

-- Using the toString:
print(type(toString(15))) -- string

Very simple. It would basically be a table, but it's a userdata, being able to create new unofficial services, or replacing.

Ending

All functions are taken from the Roblox Developer Hub, this tutorial will be updated if update any functions mentioned or add more information.