What are metatables for and how to understand them?

Hello, Developers
I came here to ask how do metatables function? I am developing on Roblox for a 2 years and I always wanted to learn metatables but sadly I could not because I did not find any clear explanation of them anywhere. Because that DevForum is full with better and more experienced developers than me, I want to hear your guys suggestions how can I start using them.


Metatables allow us to store metadata about data and alter the behaviour of data. Roblox only allows us to give tables a metatable.

Normally, tables only have a few operations. We can associate a key with a value, get the value associated with a key, and check for strict equality between two tables. However, we cannot subtract, multiply, check if one table is less than another table, etc. Metatables allow us to add this functionality.

It would be wrong to think of a metatable as something separate from any other table. Tables do not have a property of being a metatable; more so, all tables may be made the metatable of some datum without altering their own properties. When a table is first constructed, it has no metatable. With that being said, to give a table a metatable, we do:

local t = {}
local mt = {}
setmetatable(t, mt)
-- mt is the metatable of t.

Alternatively, since setmetatable returns the first argument, we can do:

local t = setmetatable({}, {})

We can get the metatable of a table with getmetatable:

print(getmetatable(t)) --> table: ...

t now has a metatable, but, so far, nothing about it has changed. To change the behaviour of data, we need to add certain metamethods to its metatable. Let’s say we wanted to change how the the table was converted to a string: instead of giving the location of the table in memory, we want the stringified version of the table to give the value of its "Name" key.

When tostring is called on a datum, Lua first checks if the datum has a metatable, and if that metatable has __tostring metamethod (that is, a key called "__tostring"). If so, Lua will get the value of that metamethod (which should be a function) and call it with the datum being operated on passed as the only argument. The operation will evaluate to whatever the function returns. As I’ve already established, to add a metamethod to a metatable, we simply assign a key with a valid metamethod name to an appropriate value:

local t = {}
t.Name = "John"
print(t) --> table: ...
-- print calls tostring under the hood, which, before we give t
-- a metatable with the appropriate metamethod, converts t
-- to a string normally.
setmetatable(t, {
    __tostring = function(t)
        return t.Name
print(t) --> John
-- this time, when print calls tostring, the metamethod overrides
-- the normal behaviour, returning the "Name" element of whatever
-- table is passed to the function.

The most commonly used metamethod is __index, which allows us to implement object-oriented inheritance, but there are many more metamethods we can use. You can learn more about them with the following resources:


First, I would like to start this reply by saying thank you for taking your time to help me, I definitely learned something from this I will read it multiple time and I hope I will understand it more.


Any idea what they visually look like? I just don’t have a clear image except what I guess is a table with tables with extra beneficial features of manipulations and storing magic. Compared to a standard table with fewer features.