Basic Lua Tables 101

All About Tables
-Part One: Referencing

Lua has a lot of things done for you, which is great! Referencing any object in the game world can be easily done. Referencing variables are just as easy. Just like how normal variables can be defined with the name you are assigning it to and the value it holds, tables can be defined in different ways.

Of course, variables can be local and global, basically meaning that local variables can only be accessed within the block it is declared in, and global variables can be used wherever in a script you want. Tables can hold integers, functions, strings, and even more tables within! (which are also known as nested tables) Values inside of tables are not defined with local in front, since it will result in a syntax error. Tables mainly use {curly brackets} to define each
variable within. A typical line of code involving referencing tables can look something like this:

local myTable = { Color = Color3.new(1, 1, 1), Name = "ROBLOX" }

Using spaces in-between the curly brackets is not necessary, but is useful for when you move onto other coding languages.

As you can see, you have to separate defined variables inside of the table with a comma so the code handler can read this code and see where the two different variables are. Not putting a comma will result in a syntax error.

Another way to define a table is very similar to changing the properties of a part. You can reference it in multiple lines, and you can easily change values on-the-go. To reference, simply define the table and just put two curly brackets next to each other. An example of this second type of
table definition:

local myTable = {}
myTable.Color = Color3.new(1, 1, 1)
myTable.Name = "ROBLOX"

As you can see, the definition takes up multiple lines but looks nicer to the eyes and is very similar to object properties.

-Part Two: Usage
Usage of tables can be very similar to reading and writing to object properties. One way to read from a table is to simply get the name of the table, and then the name of the property you want to read/write to after. Reading/writing to it would work the same on both types of the table defining.
It would look something like this:

local myTable = { Name = "Name", Color = Color3.new(1, 1, 1) }
myTable.Color = Color3.new(0, 0, 0)
myTable.Name = "NewName"

(Keep in mind that you have to read the values inside of the table like how you read the values of an object’s property. For example: print(myTable.Name). Printing the table itself will result in the hashed version of the address assigned to the table. It’s possible to circumvent that by using the Beta expressive output window, which should show the contents of the table printed.)
Now if you try printing the name and color before you change the variables, it should result in:

“Name” 1, 1, 1

Now if you print the name and color after you change the variables, it should print:

“NewName” 0, 0, 0

Another way to read from a table is by putting the table name and the numbered place it comes inside of closed square brackets. Remember that if the value you are trying to print isn’t a key, then it should print out the value. There are ways to read the contents of a keyless table. Those ways are explained in the script below:

--// This is a table without keys that are assigned to values.
local myTable = { "a", "b" }

--// This is a table that has keys assigned to values.
local myTable2 = { Name = "a", Description = "b" }

--// You can read the contents of a keyed table by either putting
--// brackets with the name inside (as a string) or by reading it
--// like a property value.
print("Table 2: "..myTable2["Name"]) -- should print the value of the Name key
print("Table 2: "..myTable2.Description) -- should print the value of the Description key

--// It is not possible to read the contents of a keyless table like
--// a property value since there are no keys assigned to it. The
--// aforementioned way of reading a keyless table by putting it's
--// ordered position inside of a bracket is the way to go.
print("Table 1: "..myTable[1], myTable[2])

You can also read the number of values within a table since ROBLOX has a handy-dandy operator/tag you can insert. Just put a hashtag in front of the name of the table, and it should return an integer which is the number of values within a table. This can be useful for debugging or other useful things.
This can be used with any kind of table. However, keyed objects will be skipped.
A typical line of code utilizing this would look like this:

--//
local myTable = {
	"a",
	"b",
	c = "c",
	"d"
}

print(#myTable)

This will print “3” since there are three keyless properties defined within the table.

There are more things you can do with tables, such as functions utilizing the (self) self-defined variable and table manipulation functions.
However, that will be for another tutorial. If you want to read more about tables, I recommend looking further on the Developer Hub to learn more about tables and specific functions related to them.

Edit: To clarify what keys are, just think of them as variables for the table.
If you’re still confused on what tables are, I recommend reading Jackscarlett’s more beginner friendly and analogous tutorial, linked here.

local myTable = {
	keyedValue = "Hello World!"
--// ^^^ 'keyedValue' is the key itself. You can use the
--// assignment operator to assign the key a value. In this case,
--// that value is 'Hello World!'
}
6 Likes

It actually prints the address of the table. print{ Property = "value" } prints table: [address of the table]

Actually they both print nil as it’s getting the property of number 1 and 2. myTable.Color and myTable.Name prints the Color property and the Name property respectively.
Also dictionaries are unordered in Lua. (as you can see this by using for key in pairs(table_value))

Length operator (#) counts the length of an array part of the table and it doesn’t include non-integral indexes of a table, not the number of properties so it’ll print 0
image

3 Likes

This is simply not true, their name is nested tables. Metatables are assigned through setmetatable() and hold methods to be invoked on specific events.


With the new expressive output window beta, it does infact print its members. This should be noted on the topic until it goes live.

5 Likes

Another teeny tiny nitpick, the displayed address is not actually the table’s address, it’s a hashed version of it. Not sure if this really matters in Roblox, but it’s done to prevent data corruption exploits.

2 Likes

Thank you for the response! I’ve fixed your nitpicks and problems with the post and hopefully it should be more informative than it is misleading. :smiley:

This part bothers me a bit. Tables cannot be local or global, the variable they are assigned to can. Tables are referenced objects, meaning you create a reference to the same table when assigning it to a variable.

You should change “tables” to “variables”.

3 Likes

This is untrue. You can have mixed tables with their indices being numbers, strings, other tables; in short, any referenced objects, numbers and booleans (this excludes NaN and nil). The thing that will happen when you use # is it will return the number of objects indexed with a number (it is actually more complicated, but I won’t go into details).

local testtab = {}
local tab = {
  1,2,3,

  test = 4,
  test2 = 5,
  [workspace] = 6,
  [testtab] = 7,
}

print(#tab) -->3
print(tab[workspace]) -->6
print(tab[testtab]) -->7
2 Likes

Boolean keys are fine.

local tbl = {[false]=1,[true]=2}
print(tbl[false]) --> 1
print(tbl[true]) --> 2

Also, NaN values are not valid keys

local tbl = {}
tbl[0/0] = 1 -- table index is NaN

All values except nil and NaNs are valid table keys.

2 Likes