Tables

Lua has exactly one data structure, and it does the job of arrays, dictionaries, objects and namespaces all at once.

Array-like

A table literal with no keys builds a sequence, indexed from 1, not 0.

local fruits = { "apple", "banana", "cherry" }

print(fruits[1])   -- apple, indexing starts at 1
print(#fruits)     -- 3, the length operator

Dictionary-like

local luak = {
    name = "Luak",
    version = "5.5.1",
    multiplatform = true,
}

print(luak.name)        -- dot syntax
print(luak["version"])   -- bracket syntax, same thing

t.key and t["key"] are exactly the same operation. The dot form is just sugar for a string key.

pairs versus ipairs

ipairs walks the 1..n array part in order and stops at the first nil. pairs visits every key in the table, array part and dictionary part alike, in an unspecified order. Use ipairs when you mean "the list part", pairs when you mean "everything".

for key, value in pairs(luak) do
    print(key, value)
end

The length operator has a rule

#t is only well-defined when the array part has no holes, no nil in the middle of the sequence. A table with a gap has an undefined length: do not rely on #t for sparse tables, use table.insert/table.remove to keep the sequence dense instead of assigning nil into the middle of one.

Nesting

local project = {
    name = "Luak",
    targets = { "jvm", "native", "js", "wasm" },
    org = { name = "Basalt" },
}

print(project.org.name)     -- Basalt
print(project.targets[1]) -- jvm

Objects, without a class keyword

A table plus functions that take it as self, the pattern from Functions, is how Lua does objects. There is no separate class syntax: metatables extend this further, but that is beyond an introduction.