__index
is a metamethod and it fires when a table is indexed with a key, to which nothing is stored, so it would normally be nil
. The point of metatables is to expand the functionality of tables. __index
helps us respond or point with our own code.
The process is handled internally and exists in vanilla lua. If __index
is pointed to a function, it’s going to automatically send you the table metatable is attached to, and the indexed key.
local cars = {}
setmetatable(cars, {
__index = function(tabl, key)
return "We don't have that car."
end,
})
cars["Ford"] = true
print(cars["Ford"]) --> true
print(cars["Audi"]) --> We don't have that car.
-- after buying Audi
cars["Audi"] = true
print(cars["Audi"]) --> true
We can also point to another table. For example:
local cars = {}
local sportsCars = {
["Porsche"] = true;
}
setmetatable(cars, {
__index = sportsCars
})
print(cars.Porsche) --> true
Should a car not exist in cars
, __index
will point to sportsCars
and look there before returning nil
.
This is particularly useful in object oriented programming (OOP). We essentially return a customized table object and set a metatable linking it back to the class. So if someone tries to call a function on our returned object and it’s not found there, index will search for it in the class.
__newindex
is similar, but fires when it detects an attempt to add a new value to key that previously held a nil
value. In the function it will automatically pass table
, key
and value
. At that point we can decide whether to allow the change in the table or not. If we don’t, we can simply return anything, but if we do, we have to do some raw writing - writing to the table without waking metatables.
__index = function(self, key, value)
rawset(self, key, value)
return;
end,