Same table, different job. Instead of numbering the slots, you name them — and now one table can describe a whole thing rather than a sequence of things.
local ship = { name = "Skynest", crew = 4, online = true }
print(ship.name)print(ship["crew"])print(ship.captain)Skynest4nilship.name and ship["name"] are the same thing written two ways. The dot is shorthand and only works for names you could use as a variable; the brackets work for anything, which is what you need when the key is in a variable: ship[whichField].
A key that was never set is nil. By now you should expect that, and you should also expect that nobody warns you. A typo in a field name behaves exactly like a typo in a variable name.
This is worth stating plainly, because it is where Lua is genuinely unlike most languages. A list and a record are the same kind of thing. { "Ada", "Bo" } is shorthand for a table with keys 1 and 2. The numbers were keys all along.
Which means one table can hold both at once, and # and ipairs simply ignore the named keys. That is occasionally useful and more often confusing, so keep your lists and your records separate until you have a specific reason not to.
pairs visits every key, named or numbered. Its sibling ipairs only walks 1, 2, 3 and stops.
local ship = { name = "Skynest", crew = 4, online = true }
for key, value in pairs(ship) do print(key, value)endonline truecrew 4name SkynestRead that caption again: the order is not guaranteed. It is not alphabetical, it is not the order you typed them, and it can differ between one Lua and another — the same file gives a different order in plain Lua than it does in LÖVE.
So never rely on it. If you need a predictable order, collect the keys into a list, sort that, and walk the sorted list. It sounds laborious and it is four lines. You will write it in Task 3, and it is the standard Lua idiom rather than a workaround.
A value can be another table, all the way down. This is how you describe anything with structure.
local ship = { name = "Skynest", bay = { docked = 2, capacity = 6 },}
print(ship.bay.docked)print(ship.bay.capacity)
ship.bay.docked = 3print(ship.bay.docked)263One caution. ship.bay.docked only works if ship.bay actually exists. If it is nil, you are asking nil for a field, and that finally is a real error — one of the few things in Lua that stops your program rather than shrugging. Activity 1.12 covers what to do about it.
Records are not fixed shapes. Assigning to a new key adds it, and assigning nil removes it — there is no separate delete.
local ship = { name = "Skynest" }
ship.charge = 98print(ship.charge)
ship.charge = nilprint(ship.charge)98nil"Set to nil" and "was never there" are indistinguishable, which is the price of not having a delete. It is also why pairs skips it afterwards — as far as the table is concerned, the key is gone.
Activity 1.2 warned you that leaving off local makes a variable global. Here is what that actually means.
shipName = "Skynest"
print(_G.shipName)print(_G["shipName"])SkynestSkynestEvery global is a key in one ordinary table called _G. Writing shipName = 'Skynest' is a table assignment. So is calling print — it is a lookup of the key print in _G, and string.format is a lookup of format in a table stored under string.
Two things fall out of that. A misspelled global returns nil because you looked up a key that was not there — it was never a special case. And globals are slower than locals because every use costs a table lookup, while a local is just a slot.
Do not write to _G on purpose. It is here so the language stops looking like it has arbitrary rules. Nothing in Lua is a special case if you know it is tables the whole way down.
Start a fresh main.lua. You are describing one ship properly, rather than with five loose variables like Activity 1.2 did.
ship.captain, which you never set. Confirm it is not an error.-- main.lua - Skynest ship record
local ship = { name = "Skynest", crew = 4, online = true,}
print(ship.name)print(ship.crew)print(ship.captain)Skynest4nil-- main.lua - Skynest ship record
local ship = { name = "Skynest", crew = 4, online = true, bay = { docked = 2, capacity = 6 },}
print(ship.name)print(ship.crew)print(ship.captain)
print("Docked:", ship.bay.docked, "of", ship.bay.capacity)
ship.bay.docked = ship.bay.docked + 1print("Docked:", ship.bay.docked, "of", ship.bay.capacity)Skynest4nilDocked: 2 of 6Docked: 3 of 6nil.type().pairs — otherwise your output will not match, and it will not match differently on different machines. This task is Activities 1.9 and 1.10 combined, which is the point.-- main.lua - Skynest ship record
local ship = { name = "Skynest", crew = 4, online = true, bay = { docked = 2, capacity = 6 },}
print(ship.name)print(ship.crew)print(ship.captain)
print("Docked:", ship.bay.docked, "of", ship.bay.capacity)
ship.bay.docked = ship.bay.docked + 1print("Docked:", ship.bay.docked, "of", ship.bay.capacity)
ship.charge = 98print("Charge:", ship.charge)
ship.online = nil
local keys = {}for key in pairs(ship) do table.insert(keys, key)endtable.sort(keys)
for _, key in ipairs(keys) do print(key, type(ship[key]))endpairs loop with one that prints only the fields that are not tables, so nested structures do not clutter the readout.type(_G) and _G.print == print. Both answers should now be unsurprising.Your finished file should produce this.
Skynest4nilDocked: 2 of 6Docked: 3 of 6Charge: 98bay tablecharge numbercrew numbername stringFour keys, alphabetical, and online is not among them. Note that bay reports as a table — a field holding a whole other structure looks no different from the outside, which is the property the next activity builds on.