Lua Cheatsheet
Metatables and OOP
Use this Lua reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
__index for Prototypes
local Account = {} Account.__index = Account function Account.new(balance) return setmetatable({ balance = balance or 0 }, Account) end function Account:deposit(amount) self.balance = self.balance + amount end local a = Account.new(10) a:deposit(5)
The table stores state. The metatable's __index points method lookup back to Account, creating prototype-style objects.
Constructor Pattern
local function new_user(name) return { name = name, active = true, } end
Not every data shape needs metatables. Plain constructor functions are easier to inspect and serialize.
Operator Metamethods
local Vector = {} Vector.__index = Vector function Vector.new(x, y) return setmetatable({ x = x, y = y }, Vector) end function Vector.__add(a, b) return Vector.new(a.x + b.x, a.y + b.y) end function Vector.__tostring(v) return string.format('(%g,%g)', v.x, v.y) -- %d errors on floats in 5.3+ end
Common metamethods include __index, __newindex, __call, __tostring, __eq, __lt, __add, __sub, and __len.
Inheritance
Chain __index: a miss on the instance falls back to the class, and a miss on the class falls back to its parent.
local Animal = {} Animal.__index = Animal function Animal.new(name) return setmetatable({ name = name }, Animal) end function Animal:speak() return 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) -- rebrand the instance as a Dog end function Dog:speak() return self.name .. " barks" end local d = Dog.new("Rex") print(d:speak()) -- "Rex barks" (found on Dog) print(d.name) -- "Rex" (found on the instance)
Lookup walks instance → Dog → Animal; each level of depth adds a lookup on a miss, so keep chains short.
Read-Only Tables
local function readonly(t) return setmetatable({}, { __index = t, __newindex = function() error('attempt to modify read-only table', 2) end, }) end
The proxy itself is empty, so pairs over it yields nothing. Lua 5.2–5.3 let you add __pairs = function() return pairs(t) end to fix that, but Lua 5.4 removed the __pairs metamethod — expose the backing table or an explicit iterator function when callers need to loop.
__newindex Trap
__newindex only fires when assigning a missing key on the table. If the key already exists, Lua writes directly unless you proxy through a separate storage table.
Equality Caveat
The __eq metamethod is only used when both operands have compatible equality behavior. For domain data, explicit comparison functions are often clearer.
Module Export Pattern
local M = {} local function private_helper() end function M.public_api(value) private_helper() return value end return M
Keep private helpers local and return only the public API table. This keeps modules predictable and avoids global pollution.