Metatables are tables that describe the function of tables. If we look at the example below, we’ll see what happens.
local tab = {}
local metaTab = {name = "Joe"}
setmetatable(tab, metaTab)
print(tab.name)
> nil
This is because metatables don’t act as inheritance methods, but rather have what we call “metamethods”, which are similar to pythons dunder/ magic methods. These are what you’ll be confusing inheritance with. You can read up on all of the metamethods here, however I’ll be talking about the one you got mixed up with, which is the __index metamethod.
This metamethod basically says that whenever an index is not found within the table, it’ll look to whatever the __index’s metamethod is set to. For inheritance, it tends to be set to itself and that way it can then use all methods, functions etc that the table has, but it can also work as such:
local tab = {name = "Joe", Letter = "A"}
local metaTab = {__index = "Hamster"}
setmetatable(tab, metaTab)
print(tab.name, tab.Letter) --> Joe A
print(tab.DESTROY) --> Hamster
First thing, just think of metatables as an extra functionality to tables
Now this metatable is something like your normal table: {}. However they have certain metamethods which are just functions, to put it bluntly.
So what happens when you call setmetatable?
local table = { }
local metaTable = { }
setmetatable(table, metaTable)
Now what will this do? Some magic stuff nani?
nope
print(table) -- {} bruh
Well that happens because your metatable has no functions or metamethods. So let’s add some metamethods.
__index
The most commonly used metamethods is __index. What it does is redirect to this another table when you index a variable that is nil in the table the certain metatable is attached to.
local boringTable = {}
local metaTable = {__index = {Admin = Mystxry12}}
setmetatable(boringTable, metaTable)
print(boringTable.Admin) --Mystxry12
So when you try to index the variable Admin in the boringTable, normally it would return nil because, no kidding, its not present in that table. However it prints Mystxry12 and why does it?
Because of our metatable of course! You might have noticed that our metatable’s __index= a table with the variable we tried to index. So what happens is this:
boringTable tries to index Admin and returns nil, since it is not present.
but then our __index gets called, as it does everytime you try to index smth, and it searchs inside of the table we attached it to, and finding that Admin exists, returns the corresponding value.
I wouldn’t declare a local variable named “table”, you’d end up overriding access to the table library from code inside of the scope of that local variable.
local table = {1, 2, 3}
table.clear(table) --errors
local tables = {1, 2, 3}
table.clear(tables) --clears table
print(#tables) --0
Yea man, after I finished writing, I was like oops that’s an issue, but then I was too lazy to edit it XD. Would b doing it rn, thnx 4 pointing it out m8.
Quick piece of advice, it’s not only __index that you can use, but other too, which can be found here. __newindex, __mode and rawset and rawget are among the most powerful and commonly used ones in the community.
__index need not necessarily be pointing to a table, for instance, you want to return smth else, when you index a certain variable. SO you can do this:
smth = {}
setmetable(smth, {__index = function(table, index)
if index == "Hacks" then
return "No hacks lol"
end
end)})
print(smth.Hacks) -- No hacks lol
__newindex fires everytime you try to rewrite a value, like smth.Admin = "Lol". Similar to __index, but it can only take a function with the @paramstable, index, value,.