Metatables
By the end of this lesson you'll use tables as both arrays and dictionaries, customise how they behave with metatables and metamethods, and build your own classes with inheritance — the foundation of every serious Lua program.
Learn Python, JavaScript, Java and more with free interactive lessons, real projects and AI-powered help. Beginner-friendly.
Part of the free Lua course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Think of a table as a sheet of paper holding your data, and a metatable as a sticky note of instructions clipped to it. Normally Lua just reads the paper. But when something unusual happens — you ask for a row that isn't written down, or you try to add two sheets together — Lua reads the sticky note to find out what to do. The sticky note doesn't store data; it stores behaviour . That single idea — "look at the manual when you hit something unexpected" — is how Lua delivers default values, operator overloading, and full object-oriented programming, all from one humble data type.
1. Tables: Lua's One Data Structure
Lua has exactly one built-in data structure: the table . Remarkably, the same table is both an array (a numbered list) and a dictionary (named key → value pairs). The one rule that trips up newcomers: Lua arrays start at index 1 , not 0. You add and remove with table.insert and table.remove , and you measure length with the # operator. Read this worked example and run it before moving on.
Your turn. The snippet below is almost complete — fill in the three ___ blanks using the hints, then run it and check it against the ✅ Expected output comments.
2. Metatables & Metamethods
A metatable is an ordinary table whose special keys — called metamethods — tell Lua what to do in situations it doesn't otherwise handle. You attach one with setmetatable(t, mt) and read it back with getmetatable(t) . The most important metamethod is __index : when you read a key the table doesn't have, Lua consults __index instead of giving you nil — perfect for defaults and inheritance. Others let you intercept writes ( __newindex ) or redefine operators like + ( __add ), == ( __eq ), and printing ( __tostring ).
Now you try overloading operators. Finish the Money type below so that + adds two amounts and print shows a £ sign. Fill in the two blanks:
__index can be a table (the usual case — Lua looks the missing key up inside it) or a function that Lua calls as __index(table, key) to compute a value on demand.
Use the table form for fixed defaults and class methods; reach for the function form when the fallback must be computed each time.
3. Building OOP with Metatables
Lua has no class keyword, yet it has full object-oriented programming — you assemble it from tables and metatables. The recipe: make a table for the class, set Class.__index = Class so instances inherit its methods, and write a constructor (by convention called new ) that returns a table whose metatable is the class. Define methods with the colon ( function Animal:speak() ), which quietly adds a first parameter called self — the instance the method was called on. Inheritance is just one more metatable: point a subclass's __index at its parent.
No blanks this time — just a brief and an outline. Build the class yourself, run it, and check your output against the comment. This is the exact shape of objects you'll write in real Lua programs and games.
Practice quiz
At what index does a Lua array start?
- 0
- -1
- Any number
- 1
Answer: 1. Lua tables are 1-based; the first element is t[1].
What is Lua's only built-in data structure?
- The table
- The array
- The list
- The struct
Answer: The table. The table serves as both array and dictionary in Lua.
Which function attaches a metatable to a table?
- addmeta(t, mt)
- setmetatable(t, mt)
- meta(t, mt)
- withmeta(t, mt)
Answer: setmetatable(t, mt). setmetatable(t, mt) attaches mt to t and returns t.
Which metamethod supplies a value for a missing key?
- __newindex
- __get
- __index
- __missing
Answer: __index. __index is consulted when a read finds no key on the table.
Which metamethod overloads the + operator?
- __plus
- __sum
- __concat
- __add
Answer: __add. __add defines what a + b does for tables.
What does dog:speak() pass as a hidden first argument?
- self (the dog)
- nil
- the class table
- the method name
Answer: self (the dog). The colon passes the receiver as self automatically.
Which line lets instances find their methods on the class?
- Class.methods = true
- Class.__index = Class
- setmetatable(Class)
- Class.self = Class
Answer: Class.__index = Class. Setting Class.__index = Class makes instances look up methods on the class.
Which metamethod intercepts SETTING a new key?
- __set
- __index
- __newindex
- __write
Answer: __newindex. __newindex runs when you assign to a key the table doesn't already have.
What does the # operator measure on { "a", color = "red" } ?
- 1 (only the array part)
- 2
- 0
- The number of keys
Answer: 1 (only the array part). # counts only the consecutive integer (array) part, ignoring string keys.
Which metamethod customises how a table is printed?
- __print
- __show
- __display
- __tostring
Answer: __tostring. __tostring controls the output of tostring() and print().