Lua has no built-in class declaration, but tables have identity and mutable state, while functions and metatables provide behavior. Together they support several object models without forcing one on the language.
Methods and self
The colon syntax passes the receiver as the first argument:
1 | local Account = {} |
The instance delegates missing fields to Account through __index, so methods do not need to be copied into every object.
Inheritance
A derived class can itself delegate to a base class:
1 | local Savings = setmetatable({}, { __index = Account }) |
Multiple inheritance is possible with a custom __index function that searches several parents, but name conflicts and lookup cost grow quickly. Composition is often easier to understand.
Private state
Lexical closures provide privacy that callers cannot bypass through ordinary table access:
1 | local function newCounter() |
This creates new closures per object, trading memory for strong encapsulation. A weak-key table keyed by public objects is another way to hold private data.
Single-method objects
Sometimes an object needs only one operation. Return a closure directly instead of constructing a class:
1 | local function newAccumulator(total) |
Choose the smallest model that expresses the ownership and behavior clearly. Lua’s flexibility is useful, but consistency within a codebase matters more than imitating every feature of a class-based language.