Hard Written By little5

Metatable Tutorial Created on: 01-01-2019

A basic overview of how metatables work.

Overview:

This tutorial will go over the basic concepts of metatables and their uses.

Prerequisites:

  • The basics of Lua as a language
  • Table manipulation
  • Functions and callbacks
  • The self keyword

    What are metatables?

    A metatable, at it's most basic definition, is a table with a metamethod attached to it. A metamethod is a sort of event trigger that calls a function when a certain operation is performed on the metatable, hence the name "meta".

Meta: Pertaining to a thing's self (in this instance, a table) Table: A container that stores values

In the first example we will create a metatable with the index metamethod attached. The index metamethod is called when you index a nil value in a table, and can return something in it's stead.

To create a new metatable, you use the setmetatable() function:

local t = {}

function setDefault(t, d) -- from Programming in Lua, 13.4.3 - Tables with Default Values
	local mt = {__index = function() return d end}
	setmetatable(t, mt)
end

local values = {
	foo = "foo";
	bar = "bar";
}

print(values.blah) -- nil

setDefault(values, "blah")

print(values.blah) -- blah

This code defines a function that, when a table and a value is passed in, sets any nil value in that table to return what was passed in. We can see this in line 12 in that when we print values.blah, it prints nil. However, when we call setDefault and pass in values and "blah", any time you index a nil value, the metamethod will return "blah".

Another useful metamethod is the newindex metamethod. Like the index metamethod, it's fired when you try to assign a value that was originally nil.

function makeReadOnly(t)
	local mt = {__newindex = function() return error("Table is read-only.") end}
	setmetatable(t, mt)
end

local t = {}
t.foo = "foo"
makeReadOnly(t)
t.bar = "bar" -- will error: "Table is read-only."

There are many other metamethods we can use, but in practice, most of them aren't particularly useful on Roblox. These include add, sub, mul (multiplication), div (division), unm (negation), and pow (exponentation). Here's an example of how __add is used:

local mt = {
	__add = function(t0, t1)
		local rt = {}
		for i = 1, math.min(#t0, #t1) do
			table.insert(rt, (t0[i] + t1[i]))
		end
		return rt -- returns a table with the sums of each of the elements of the original tables
	end
}

local t0 = setmetatable({1, 2, 3}, mt)
local t1 = setmetatable({3, 2, 1}, mt)
local t2 = t0 + t1

for i, v in ipairs(t2) do 
	print(v) -- 4 x3
end

The rest of them follow the same principle: the function takes in two tables and can return a value.

Summary:

In this tutorial, you learned how to use the index metamethod, the newindex metamethod, and the arithmetic metamethods. With these, you can make default values for tables, make read-only tables, and make it so that you can add two tables together to get their element's sums.

At their core, metatables are like event handlers; they take in events such as indexing a nil value, run the context through a function, and return a result.

Hard Written By little5

See little5's profile on Roblox

Discussion