Stack MetaTables

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. :wave:

To be real with you it’s pretty cool! I still don’t have ideas on using this module, but I can obviously get a better learning from it!

I see why. But mostly you could say that people will use this for learning instead of using it because I don’t see people having any use of this in their games.

Still, amazing work, good luck on your future projects!

1 Like