4. Tables and Loops¶
Learning Objectives
- be familiar with Lua tables
- understand the uses of metatables and metamethods
- understand how to use
while
andfor
loops
Tables as Associative Arrays¶
Tables in Lua are neither values nor variables but objects. The table type implements associative arrays, which are arrays that can be indexed by any value except nil
.
Tables do not have a fixed size and can be changed dynamically. We use tables to represent ordinary arrays, dictionaries, sets, queues and other data structures. All tables are created with the {}
constructor expression. Values are accessed and assigned with the []
operator.
-- creating a table of 3 elements indexed by 1,2
local a = {}
a[1] = "apples"
a[2] = "bananas"
-- accessing the 2nd element
print(a[2]) -- output: "bananas"
Common mistake
Unlike in other languages, accessing unset indexes returns nil
instead of throwing errors
Arrays¶
Tables can be used as arrays simply by adding in values into the constructor. Note that tables in Lua are by default 1-indexed.
-- using constructors to create and initialize arrays in a single expression
local squares = {1, 4, 9, 16, 25, 36, 49, 64, 81}
Changing index
We can also start an array at index 0, 1, or any other value by just manually setting indexes:
-- starts at -5 and increments by 1 each index
local squares = {[-5] = 1, 4, 9, 16, 25, 36, 49, 64, 81}
However, we recommend always starting arrays with index 1 to allow the Lua standard library functions to work properly.
Dictionaries¶
Tables can also be used as dictionaries, allowing you to associate keys with values. These keys can be strings, numbers, or any other type except nil
-- using constructors to create and initialize dictionaries in a single expression
local shoppingList = {
["apples"] = 3,
["oranges"] = 4
}
If the keys are valid Lua identifiers (i.e. strings that are alphanumeric without spaces or special characters), we can omit the []
during table creation:
Dot Syntax¶
Dictionaries with Lua identifier keys can be also be quickly indexed by the dot syntax as shorthand for accessing or modifying the table.
-- creating a table with string keys
local person = {name = "Alice", age = 25}
print(person.name) -- output: "Alice"
person.age = 26 -- modifying person["age"]
Metatables¶
Tables in Lua can have a special feature called metatables, which allow you to define custom behaviors for operations performed on the table. Metatables enable powerful features like operator overloading, handling undefined keys, and more.
Setting a metatable¶
You can assign a metatable to a table using the setmetatable
library function:
Metamethods¶
Metatables can define metamethods - special fields that control the behaviour of a table. These are similar to dunder methods in Python. Common metamethods include:
__index
(define what happens when accessing a nonexistent key)__newindex
(define what happens when assigning to a nonexistent key)__add
,__sub
,__mul
, etc. (define how operators behave with the table)
For instance, here we use __index
to provide a default value:
local point = {}
local defaults = {x = 0, y = 0}
local mt = {__index = defaults}
setmetatable(point, mt)
print(point.x, point.y) -- output: "0 0"
point.x = 10
print(point.x, point.y) -- output: "10 0"
We will later cover how to use metatables and metamethods to simulate classes and OOP-like behaviour in Lua.
for
loops¶
for
loops are used to iterate over a finite sequence of numbers or values.
Numeric for
loop¶
Numeric for
loop is used to iterate over a sequence of numbers, and it includes a start value, stop value, and optional step value (the increment per iteration)
Numerically iterating over arrays
We can use the numeric for
loop to iterate over arrays, similar to how it would be done in other programming languages like so:
ipairs
¶
ipairs
is a standard library function which helps to iterate over a table until the first nil
is found. We typically use it to traverse continuous arrays. It is the idiomatic way to traverse arrays in Lua.
ipairs
¶
pairs
is a standard library function which helps to iterate over all key-value pairs in a table. We typically use it to traverse dictionaries.
-- iterate over every key-value pair in the dictionary
for key, value in pairs(t) do
-- loop body
end
Generic for
loops
Luau also has generic for
loop syntactic sugar which automatically determines which standard library function, ipairs
or pairs
, to use when dealing with a table. It is the idiomatic way to traverse tables in Roblox.
while
loops¶
while
loops are used when you want to repeat execution of the loop body for as long as the condition stays true.
repeat-until
loops¶
repeat-until
loop is similar to a standard while
loop except that that the loop body is guaranteed to be executed at least once, and repeated until the condition is reached