Tips
Braces
{ }
in Lua means the creation of a new table.By Samir Tine, published on December 2021
Thanks for taking the time to read the first and second part of this tutorial on learning programming with Luart.
Now we'll talk about complex Lua types. Let's get started !
If you were wondering what a table in a programming language did, then you're not alone! Lua tables are similar to real tables in everyday life:
on a table, you can put plates, forks, glasses, etc. In Lua, however, you will find other values: strings
, numbers
, booleans
, and even other tables
.
We're not talking about furniture here, but containers.
In Lua, a table is a container, which means that it's a type of value that stores other values.
Do you remember the Luart runtime library ?
I had hinted at a real library (and now we know of two aisles: sys
and string
). These aisles are actually Lua tables, that contains functions.
As you can see, tables are a simple way to store and organize values.
Here is an example that shows how to create a table :
print({ "orange", "banana", "apple" })
print(sys.beep)
In this example, a table that contains 3 strings is created using braces. Lua will print to the screen table: XXXXX
(where XXXX is an hexadecimal value).
The content of the table will not be printed, because they are contained inside that table (remember a table is a container !).
The second line will print the beep value inside the sys
table (remember the dot !), and as you already know it's a function value. Here no sound will be emitted as we don't use the parenthesis to call the beep
function.
To access table content, we need to use the dot .
and the name of the wanted value. That means that every value stored in a table has a "name".
Lua tables are dynamic : it's possible to add or remove values inside tables at anytime. The following lines will add named values inside the sys
table :
-- Let's add the christmas date to the sys table !
sys.day = 25
sys.month = 12
sys.year = 2021
sys.message = "Happy Christmas !"
In this example, we add named values to the sys
table, from the Luart runtime library. A table "named value" is called a field in Lua.
In this case, we are adding 4 fields to the sys
table. A more convenient way to store the Christmas date in the sys
table is to use a single field like this :
sys.christmas = { 25, 12, 2021 }
The sys.christmas
field will now contain a table
with three number values. But..wait a minute...how to access those values ? What is the name of the field ?
In this case, when no field name is provided, Lua assign an integer number that starts from 1 :
print(sys.christmas[1]) -- will print 25, the first element in the table
print(sys.christmas[2]) -- will print 12, the second element in the table
print(sys.christmas[3]) -- will print 2021, the third and so on...
In fact, Lua tables are very powerful containers and use a generic key/value mechanism : each value in the table is stored using a key.
A key can be any Lua value : a string
, a boolean
, a number
, a function
, even an other table
, and, in fact, any other value, except nil
.
To get or set a table element the universal method is to use the table[key]
notation :
sys.human = { } -- sys.human is now an empty table
sys.human["gender"] = "male" -- creates a new key "human" inside that table with a "male" value
sys.human["age"] = 26 -- creates a new key "age" with a number value of 26
sys.human[1] = true -- creates a new key 1 (a number) with a true boolean value
string
, and that string begins with a character or a _
, that key is considered as a field and only in that case you can use the field
notation to access table elements :
print(sys.human) -- prints "table: XXXXX"
print(sys.human.gender) -- prints "male"
print(sys.human.age) -- prints "26"
print(sys.human.1) -- error ! "1" is not a valid field
print(sys.human[1]) -- Yes ! prints correctly "true"
print(sys.human.name) -- prints "nil", the table sys.human does not contain "name" field
Please note that indexing a table (using brackets or using the dot notation) with a key that is not contained, it returns a nil
value.
It makes sense after all, you looked for a something that does not exist. Rather than throwing an error, Lua informs you with the nil
value that the key is not valid.w
Let's go further using the nil
value with tables :
sys.humain[nil] = "something" -- error ! a nil key is not a valid key !
sys.humain.gender = nil -- change the element with key "gender" from "male" to nil
print(sys.human.gender) -- prints nil ! The "gender" key has been removed from the table !
Using a nil
value as a key is not possible, as you may have already guessed. But assigning a nil
value to a key will remove it the table. I think it's pretty well seen and logical.
On a side note, as for strings, tables can be handled with specific functions stored in the "table"
aisle of the runtime Library.
See the Lua 5.4 manual for a complete listing.
Well, that's all for the moment ! Just remember that tables are much more powerful than they seem with a degree of customization that you cannot yet imagine and which goes well beyond this tutorial for beginners.
You already know what a function is, just remember the print
function you already know.
There are plenty of functions available in the Luart runtime Library to perform various actions (create a window, choose a font, open a file, write to the console ...). Functions in Lua are values in their own right and can be used as table keys, as arguments,...
Let's see now how we can create our own function in Lua :
-- declare a function "hello" which takes no argument
function hello()
-- prints the message "Hello !" to the screen
print("Hello !")
end
-- calls the hello function
hello()
Functions are defined with the special word function
. This special word is called a keyword. It is followed by the function name, here hello
, with a pair of parenthesis ()
.
There's not much this function can do, so let's add some arguments to make it more useful. What will these arguments be? This brings us to a concept we have not discussed thus far: variables
.
In reality, a variable is simply a word attached to a Lua value. It is like a table field as we have just seen, but without the table. Here is an example:
-- declare a function "hello" which takes one argument : the variable "name"
function hello(name)
-- prints the string "Hello " concatenated with the value represented by the name variable
print("Hello "..name)
end
-- calls the hello function with one argument, a string value
hello("Sam")
In this example, the hello
function is called with the string "Sam"
as first argument. This argument is then passed to the name
parameter when calling the function.
In this case, the function just prints a message to the screen, and returns nothing. In fact, functions can return one or more values. This is done with a new keyword : return
, the following example demonstrates it :
-- declare a function "square" which takes one argument : the variable "number"
function square(number)
-- return the result of multiplying the variable "number" by itself
return number*number
end
-- prints the value returned by the "square" function called with the argument 2
print(square(2))
This function calculate the square of a number and return its result, which is then printed to the screen. In fact, this function can be used with any other number. Function are blocks of code that we can reuse at will.
Functions are values in Lua, they can for example be assigned to a field in a table :
function add(number1, number2)
return number1 + number2
end
-- create a variable "mathematic" representing a new empty table
mathematic = { }
-- add to this table a field "addition" with the add function as a value
mathematic.addition = add
-- print the result of the function mathematic.addition(1, 2)
print(mathematic.addition(1, 2))
Assigning a function value to a table key, makes that key callable using the same function value. In this example, the field addition
contains the add
function.
You may ask why field addition
has a value of add
and not add()
. The reason is simple : when declaring a function, in fact, you declare a variable with the name of the function. Using parenthesis on that variable calls the function. Check the following example :
function add(number1, number2)
return number1 + number2
end
-- add is a variable containing a function value : prints "function: XXXXX" to the screen
print(add)
-- error !! (no arguments provided : arguments number1 and number2 are nil)
print(add())
-- outputs "3"
print(add(1, 2))
Functions are particularly useful. You can reuse code by using functions rather than writing the same instructions repeatedly. They also allow you to better structure your programs.
Functions in Lua have other advanced features (table method, multiple return values, anonymous functions, variable number of arguments..) that go beyond this beginner's tutorial.
This tutorial on complex types in Lua has now come to an end, since we chose not to cover userdata
and thread
types, which are more advanced concepts.