Tutorial; Lua Tag Methods - HWRM/KarosGraveyard GitHub Wiki

Tag Methods

Lua 4's tag sytem is fairly arcane, and the manual is (in my opinion), really not helpful at all.

Tag methods share a ton in common with Lua 5.x's concept of metatables, and are in fact a precursor to that system.

💡 The usage of tag methods is to define some 'custom' behavior for a table variable.

The basic flow is:

  1. A new tag is created with newtag
  2. A method is associated with this tag and an event/operation type, using settagmethod
  3. This tag can be applied to one or more tables using settag

Each table may have at most one tag, and each tag may have only one method per event, i.e you can't have multiple hooks invoked for a "gettable" event on the same table.

An example, where we 'freeze' an input table, meaning it can no longer be modified:

--- Freezes a table, meaning it cannot be altered (except by `rawset`).
---
---@param tbl table
---@return table
function freeze(tbl)
	local t = newtag();
	local hook = function (tbl, key, value)
		print("Cannot modify frozen table `" .. tostring(tbl) .. "`");
		print("\tOccured while setting key " .. tostring(key) .. " to value " .. value);
		print("\tExisting key/value: `" .. tostring(key) .. "`: " .. tostring(tbl[key]));
	end
	settagmethod(t, "settable", hook);
	settag(tbl, t);

	return tbl;
end

local t = {
	x = 10
};

print(t.x); -- 10
t.x = 20; -- ok
print(t.x); -- 20

freeze(t);

t.x = 30; -- warning emitted, no alteration to 'x'
print(t.x); -- 20

Here we 'hijack' the "settable" operation for the table. Instead of the default behavior, we define our own totally custom behavior (the hook function).

Another example, where we may print a table value any time a script tries to access it:

--- Logs (prints) any access to the given table's values
---
---@param tbl table
---@return table
function logAccess(tbl)
	local t = newtag();
	local hook = function (tbl, key)
		local value = rawget(tbl, key); -- need to use rawget to avoid triggering this very tag infinitely
		print("Access on tbl " .. tostring(tbl));
		print("\t[" .. tostring(key) .. "] = " .. tostring(value));
	end
	settagmethod(t, "gettable", hook);
	settag(tbl, t);

	return tbl;
end

local t = {
  x = 10
};

local a = t.x; -- no logging performed on the access to 'x'

logAccess(t);

local b = t.x; -- prints the table's address & the key-val pair

A full list of available tag methods (i.e "getttable" and "settable") is in the manual.