Metatables and __index
Every table can have an associated metatable, set via setmetatable(t, mt), which defines special behaviors called metamethods. The __index metamethod is the key to inheritance: when you access a field that doesn't exist directly on a table, Lua checks the metatable's __index — if it's a table, Lua looks up the missing field there instead; if it's a function, Lua calls it with the table and key. This lookup chain is how a Lua "subclass" table falls back to a "parent" table's methods.
Cricket analogy: When a young domestic player doesn't have a signature shot yet, selectors fall back to the technique taught by their state academy coach, the way a table without a field falls back to __index's table.
local Animal = {}
Animal.__index = Animal
function Animal.new(name)
local self = setmetatable({}, Animal)
self.name = name
return self
end
function Animal:speak()
print(self.name .. " makes a sound")
end
local Dog = setmetatable({}, { __index = Animal })
Dog.__index = Dog
function Dog.new(name)
local self = Animal.new(name)
return setmetatable(self, Dog)
end
function Dog:speak()
print(self.name .. " barks")
end
local rex = Dog.new("Rex")
rex:speak() --> Rex barks (Dog's own method wins)Building a Class-Like Chain
To emulate a "class", a table (e.g. Animal) sets its own __index field to itself, so instances created with setmetatable({}, Animal) fall back to Animal for any method lookup. A "subclass" (Dog) is then given a metatable whose __index points to Animal, and Dog also sets Dog.__index = Dog, so instances of Dog first check Dog, then fall back to Animal if the method isn't overridden there. Multiple levels of this chain create arbitrarily deep inheritance.
Cricket analogy: A player's technique is checked against their franchise's playbook first, and if not found there, against the national board's general coaching manual, layering fallback lookups like a Dog-to-Animal metatable chain.
Forgetting to set Dog.__index = Dog is a common bug: without it, instances of Dog will fall back all the way to Animal for every lookup (which may still work), but Dog itself won't correctly serve as the __index for its own instances if you intended Dog-level overrides to be found first. Always set ClassName.__index = ClassName right after creating the class table.
Method Resolution Order and Multiple Inheritance
Because __index can also be a function rather than a table, Lua supports more flexible schemes than single-parent chains, including basic multiple inheritance: a custom __index function can search several parent tables in order and return the first match. This is how libraries like middleclass implement mixins, and it's also why understanding __index as "a fallback, not a copy" matters — changes to a parent table after subclassing are still visible to children, since lookups happen live at call time, not at inheritance-setup time.
Cricket analogy: A player eligible to represent either their state team or a composite invitational XI has selectors check multiple rosters in priority order, similar to a custom __index function searching multiple parent tables.
Live Lookups, Not Copies
It's important to internalize that __index lookups happen at access time, not at object-creation time — no data is copied from parent to child when setmetatable runs. If you later add a new method to Animal, every existing Dog instance immediately gains access to it too, because each field access re-walks the metatable chain. This live-binding behavior is different from class-based languages that resolve method dispatch tables once at compile time, and it makes Lua's inheritance model closer to prototype-based languages like JavaScript's older Object.prototype chains.
Cricket analogy: If the BCCI updates the DRS review rules mid-season, every match immediately follows the new rule rather than the old one being locked in at season start, mirroring how __index re-checks live, not at setup time.
setmetatable(t, mt)attaches a metatable to a table;__indexis the metamethod that enables inheritance-like fallback.- If
__indexis a table, missing key lookups redirect there; if it's a function, Lua calls it with(table, key). - The standard pattern sets
ClassName.__index = ClassNameso instances fall back to the class table for methods. - Subclassing chains
__indexfrom child to parent (e.g. Dog's metatable __index is Animal), enabling multi-level inheritance. - A custom __index function can search multiple parent tables in order, enabling mixin-style multiple inheritance.
- __index lookups are resolved live at access time, so changes to a parent table affect all existing children immediately.
Practice what you learned
1. What metamethod is primarily responsible for Lua's inheritance behavior?
2. In the standard class pattern, why do you write `Dog.__index = Dog`?
3. If Animal gets a new method added after Dog instances already exist, what happens?
4. How can Lua achieve a form of multiple inheritance?
Was this page helpful?
You May Also Like
Object-Oriented Lua
Learn how Lua uses tables, functions, and metatables to build objects, methods, and encapsulation without a built-in class system.
Modules and require
Learn how Lua organizes reusable code into modules with the require function, package.path, and the standard return-a-table pattern.
Error Handling in Lua (pcall/error)
Learn how Lua signals and catches errors using error(), pcall(), and xpcall(), instead of try/catch exceptions.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics