This module purpose is to give you an easy way to apply stacked metatables onto a table; By stacked metatables I mean, you have the ability to bind more than just one metatable to a table.
Example
local Table0 = { Abc = 123 }
local Table1 = { Def = 456 } Table1.__index = Table1
local Table2 = { Ghi = 789 } Table2.__index = Table2
Table2.__call = function()
return 123
end
require(script.StackMetaTables).setstackmetatable(Table0, { Table1, Table2 })
-- It will iterate through the array from [ 1, x ] so if you'd like to add priorities to your MetaTables, then you can set the metatable's position in the array to be closer to 1.
print(Table0.Abc, Table0.Def, Table0.Ghi) -- 123 456 789
print(Table0()) -- 123
print(getmetatable(Table0)) -- "The metatable is locked"
Module
--[[
StackMetaTables.luau
@Author: AsynchronousMatrix
@Licence: ...
]]--
-- // Types
type dictionary = { [any]: any }
type array = { [number]: any }
-- // Variables
local stackMetaTables = { }
stackMetaTables.metaMethods = {
"__index", "__newindex", "__call", "__concat", "__unm", "__add", "__sub", "__mul", "__div",
"__mod", "__pow", "__eq", "__lt", "__le", "__len"
-- __mode
-- __gc
-- __metatable
-- __tostring
}
-- // Functions
function stackMetaTables:invoke(method:string, MTs: array, ...: any): any
for _, metaTable in ipairs(MTs) do
local resolve
if metaTable[method] then
local metaType = type(metaTable[method])
resolve = if metaType == "function" then
table.pack(metaTable[method](...))
elseif metaType == "table" then
table.pack(metaTable[method][...])
else
{ metaTable[method] }
end
if resolve and resolve[1] ~= nil then
return resolve
end
end
end
function stackMetaTables.setstackmetatable(T: dictionary, MTs: array): dictionary | any
local self = stackMetaTables
local masterMetaTable = { }
masterMetaTable.__metatable = "The metatable is locked"
for _, metaMethod in ipairs(self.metaMethods) do
masterMetaTable[metaMethod] = function(T: dictionary, ...: any)
return table.unpack(self:invoke(metaMethod, MTs, ...))
end
end
table.freeze(masterMetaTable)
setmetatable(T, masterMetaTable)
return T
end
-- // Module
return stackMetaTables
The following metamethods are excluded from the module;
- __tostring
- __mode
- __gc
- __metatable
!! In order to add these metamethods into the module, you’ll have to comment out
table.freeze(masterMetaTable) -- Ln 58
and add your metamethods into the masterMetaTable
This wont be useful for the 99% of people who browse this thread, however, it might be useful for the 1% of people who want to do something like this, but do not know how to.
I couldn’t find anything online.