100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Inheritance with Metatables

Understand how Lua uses metatables and the __index metamethod to implement inheritance chains between tables.

OOP & ModulesIntermediate10 min readJul 10, 2026
Analogies

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.

lua
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; __index is the metamethod that enables inheritance-like fallback.
  • If __index is a table, missing key lookups redirect there; if it's a function, Lua calls it with (table, key).
  • The standard pattern sets ClassName.__index = ClassName so instances fall back to the class table for methods.
  • Subclassing chains __index from 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

Was this page helpful?

Topics covered

#Programming#LuaStudyNotes#InheritanceWithMetatables#Inheritance#Metatables#Index#Building#OOP#StudyNotes#SkillVeris