User:Gechy/lua tutorial
Lua tutorial
The tutorial aims to be accessible to all manner of programmers. Experienced users will read at great speed and beginners can digest the text more slowly; both can take advantage of the examples to clarify. It is thought that learning by example is the best form of learning. Please note that this tutorial assumes you are using Lua version 5.1.
Getting started
You can use the live demo to play with Lua if you don't want to install anything on your computer. For guide on how to install lua on your computer see install lua locally
Lua variable type
The variable name is the usual way to reference the stored value, in addition to referring to the variable itself, depending on the context. There are eight basic types of values in Lua: number, string, boolean, table, function, nil, userdata, thread. In Scribunto we make use of six out of the eight types available in the Lua programming language.
Numbers
The number type represents a floating-point (fractional) number. They represent real (double-precision floating-point) numbers.
Arithmetic operation with numbers
Lua allows simple arithmetic on numbers using the usual operators to add, subtract, multiply and divide.
print(2+2) -- Addition of numbers
4 -- Output
print(2-7) -- Subtraction operation
-5 -- Output
print(7*8) -- Multiplication operation
56 --Output
print(7/8) --Division operation
0.875 --Output
From the example above, you observed that the numbers are not rounded into integers. They are floating point, or real numbers.
Assignment operator
In Lua, we can assign values to variables using the = operator.
x = 7 -- = operator assigns the number 7 to the variable x.
print(x) -- function again to print out the value of x
7 -- output
From the example above, we can now use the value in x for other arithmetic operations.
x = x * 9
print(x)
63
print(x*2) -- will not change the value of x
126
print(x)
63 -- new value for X
String
Lua also uses strings (i.e. text) types. To create strings, wrap text in "double quotes" or 'single quotes'. Strings in Lua can contain any 8-bit value, including embedded zeros, which can be specified as '\0'.
print("hello") -- quoted string
hello -- output
In lua strings can be assign to a variables just like we can for numbers:
name = "John"
print(name)
John
Lua string concatenation is done using the .. operator and not the + operator shown below:
print("hello " .. name) -- the variable "name" was assigned above
hello John -- output
Boolean
Boolean values have either the value true or false. The not operator can be placed before a boolean value to invert it.
x = true -- assign true to the variable
print(x) -- invoking the print function
true -- output
print(not x) -- using the not operator
false -- inverted output
print(not false)
true -- inverted output
Boolean values are used to represent the results of logic tests. The equals ==, and not equal ~= operators will return boolean values depending on the values supplied to them
print(1 == 0) -- test whether two numbers are equal
false -- output
print(1 ~= 0) -- test whether two numbers are not equal
true -- output
print(true ~= false) -- is true not equal to false?
true
Note that for an assignment you use a single equals sign (=), but for comparison, you use a double equals sign (==). As shown in the examples above.
Tables
Lua has a general-purpose aggregate data type called a table. Aggregate data types are used for storing collections (such as lists, sets, arrays, and associative arrays) containing other objects (including numbers, strings, or even other aggregates).
Tables are created using a pair of curly brackets {}.
x = {} -- creating an empty table
print(x)
table: 0x237f670 -- output
It is normal if your table does not have the same unique identifier as in the above example.
Function
In Lua, functions are assigned to variables, just like numbers and strings. Functions are created using the function keyword. It allows you to call the same code in multiple places. Lets create a simple function to print hello:
foo = function () print("hello") end -- declare the
function
foo() -- call the function
hello -- Printed output
print(foo) -- get the value of the variable "foo"
function: 0035D6E8
You will notice that we could print the value of the variable foo (like tables). The value is a function with a unique identifier. A function can be assigned to a variable:
x = function() print("hello") end
x()
hello
print(x)
function: 0035EA20
From the example above, in lua all values are treated the same way (first-class values).
nil
nil is a special value which indicates the lack of a useful value. If you try getting a variable that doesn't exist you will get nil:
print(x)
nil --output as x is undefined
x = 2.5 --x is assigned a value
print(x)
2.5 --value of x printed out
userdata
Userdata values are objects foreign to Lua, such as objects implemented in C. These typically come about when an object in a C library is exposed to Lua.
thread
A thread value represents an independent (cooperative) thread of execution.
Dynamic typing
Lua has dynamic typing. This means that types are checked while a program is running. Like many other programming languages with dynamic typing, in Lua you don't have to specify what type a variable is. The variable knows what type it is from the value, or object, assigned to it.
a = 1
b = "hello"
c = {}
Lua we can also assign different types of values to the same variable, e.g.
a = 1
a = "hello"
a = {}
Querying type
You can use the Lua function type() to get a description of the type of a particular object.
x = "123" -- a string
print(x, type(x)) -- show the value of x and its type string
123
x = x + 7 -- add a number to the string which forces coercion
print(x, type(x)) -- again show the value and type number
130
Assignment statement
Setting the value of a variable is an assignment:
x = 1
y = "hello"
print(x,y)
1 hello
Multiple assignment
In Lua you can perform multiple assignments in a single statement, e.g.,
x, y = 2, "there" --multiple assignment
print(x,y)
2 there --output
a,b,c,d,e,f = 1,"two",3,3.14159,"foo",{ this="a table" }
print(a,b,c,d,e,f)
1 two 3 3.14159 foo table: 0035BED8
The list of values on the right is assigned to the list of variables on the left of the =. We can assign as many values as we like and they don't all have to be of the same type as seen in the example above.
However, multiple assignments come with a few limitations as described below:
Evaluation occurs before an assignment
Any expressions are evaluated first. The evaluated expression is then assigned.
i = 7
i, x = i+1, i
print(i, x)
8 7
When Lua reaches the second line it evaluates the expressions i+1 and i before anything else. After evaluation the second line becomes i, x = 8, 7. Then it performs the assignments from right to left.
Swapping values
you can use multiple assignments to swap variable values around:
a,b = 1,2 -- set initial values
print(a,b)
1 2 -- output
a,b = b,a -- swap values around
print(a,b)
2 1 -- output
a,b = b,a -- and back again
print(a,b)
1 2 -- output
Note that there is no need for a temporary variable (such as bold = b; b = a; a = bold;).
Assignment order
The order in which multiple assignments are performed is not defined. This means you shouldn't assume the assignments are made from left to right. If the same variable or table reference occurs twice in the assignment list the results may surprise you.
a, a = 1, 2
print(a)
1 -- output
In the above example, Lua does assignments from right-to-left, e.g. a=2 and then a=1. You should use separate assignment statements if the order of assignment is important to you.
Mismatched list sizes
If a value list is longer than the variable list the extra values are ignored.
a,b,c = 1,2,3,4,5,6
print(a,b,c)
1 2 3
Lua assigns the value nil to the variables without a value if a value list is shorter than the variable list.
a,b,c,d = 1,2
print(a,b,c,d)
1 2 nil nil
Numbers manipulations
Lua supports only one type of number: floating-point numbers. By default, these are double-precision floating-point numbers. However, Lua can easily be recompiled to support single-precision floating-point numbers should you so desire. If you use numbers with fractional parts (or division), they may have a rounding error. Numbers which have infinitely repeating patterns in decimal will not have them in binary, so don't assume that any fractional number is safe.
You don't use the == operator with fractional numbers since it checks for perfect equality. Remember to write your code in such a way that rounding error don't build up over time.
When your numbers are integers (with no fractional part), and they don't reach 2^53; then you won't need to worry about these issues.
Performing calculation in lua
We can use the Lua interactive command-line prompt as a calculator by prefixing an expression by =. This can be performed also on lua demo
= 1 + 2
3
Lua also understands exponent types for expressing numbers in the form <value>e<exponent> or <value>E<exponent>, which represents <value> * 10 ^ <exponent>.
= 543.21E8
54321000000
= 2.56e-4
0.000256
You can assign numbers to variables and do arithmetic:
width = 7.5
height = 12.7
= width * height
95.25
Number conversion
You can convert strings to numbers using the function tonumber(). This takes a string argument and returns a number.
= tonumber("123") + 25
148
x = tonumber("123.456e5")
print(x)
12345600
For converting integers to floating points, this calculation returns a decimal format of the converted integer:
= (16 ^ 13) + 10 - (16 ^ 13)
10.0
Coercion
Lua will automatically convert string and number types to the correct format to perform calculations. if you try to apply an arithmetic operation to a string Lua will try to convert that string to a number first. Otherwise, the operation will not work. This automatic conversion of types is called coercion.
= 100 + "7"
107 --output
= "hello" + 234
stdin:1: attempt to perform arithmetic on a string value
stack traceback:
stdin:1: in main chunk
[C]: ?
You can see the calculation succeeds where a string was converted to a number. The string "hello" cannot be converted to a number and so an error occurs. This works in Lua because it is dynamically typed.
A notable exception: comparison operators (== ~= < > <= >=) do not coerce their arguments. Ordered comparison operators throw an error when you feed them different types.
= 100 == "100"
false
= 100 ~= "hello"
true
= 100 == tonumber("100")
true
= 100 <= "100"
stdin:1: attempt to compare number with string
stack traceback:
stdin:1: in main chunk
[C]: ?
For performance reasons, you should avoid relying on automatic coercion too much. Make sure that all numbers in performance-sensitive computations (especially in inner loops) are of the proper type.
String
Strings can be defined using single quotes, double quotes, or double square brackets.
= "hello"
hello
= 'hello'
hello
= [[hello]]
hello
You can enclose one type of quotes in the other. e.g..
= 'hello "Lua user"'
hello "Lua user" -- output
= "Its [[content]] hasn't got a substring."
Its [[content]] hasn't got a substring. -- output
Double bracketed strings also have a few other special properties.
Escape sequences
Lua can also handle C-like escape sequences.
= "hello \"Lua user\""
hello "Lua user" -- output
= 'hello\nNew line\tTab'
hello
New line Tab
Escape sequences are not recognized when using double brackets, so:
= [[hello\nNew line\tTab]]
hello\nNew line\tTab
Multiline quotes
Double square brackets can be used to enclose literal strings which traverse several lines. e.g.,
= [[Multiple lines of text
>> can be enclosed in double square
>> brackets.]]
Multiple lines of text
can be enclosed in double square
brackets.
Nesting quotes
Double square brackets allow nesting, but they require one or more = inserted in the outer-most brackets to distinguish them. It doesn't matter how many = are inserted, as long as the number is the same in the beginning and ending brackets.
= [[one [[two]] one]] -- bad
stdin:1: nesting of [[...]] is deprecated near '[' -- returns an error
= [=[one [[two]] one]=] -- ok
one [[two]] one
= [===[one [[two]] one]===] -- ok too
one [[two]] one
Concatenation
Strings can be joined together using the concatenation operator "..". e.g.,
who = "John"
= "hello "..who
hello John -- output
Numbers can be concatenated to strings. In this case, they are coerced into strings and then concatenated. You can read more about coercion below
= "Green bottles: "..10 -- concatenating a string and integer
Green bottles: 10 -- output
= type("Green bottles: "..10) -- using the type function
string -- output
Doing a large number of concatenation operations may be slow because each concatenation may allocate a new string in memory.
Coercion in string
Lua performs automatic conversion of numbers to strings and vice versa where it is appropriate. This is called coercion.
= "This is Lua version " .. 5.1 .. " we are using."
This is Lua version 5.1 we are using.
= "Pi = " .. math.pi
Pi = 3.1415926535898
As shown above, during coercion, we do not have full control over the formatting of the conversion. To format the number as a string as we would like we can use the string.format() function. e.g.,
= string.format("%.3f", 5.1)
5.100
= "Lua version " .. string.format("%.1f", 5.1)
Lua version 5.1
This is an explicit conversion using a function to convert the number, rather than coercion.
String library
Lua supplies a range of useful functions for processing and manipulating strings in its standard library. Below are a few examples of usage of the string library.
= string.byte("ABCDE", 2) -- return the ASCII value of the second character
66
= string.char(65,66,67,68,69) -- return a string constructed from ASCII values
ABCDE
= string.find("hello Lua user", "Lua") -- find substring "Lua"
7 9
= string.find("hello Lua user", "l+") -- find one or more occurrences of "l"
3 4
= string.format("%.7f", math.pi) -- format a number
3.1415927
= string.format("%8s", "Lua") -- format a string
Lua
Lua expressions
Expressions are evaluated in order to perform calculations which may assign values to variables or pass arguments to functions.
We'll use the = expression shorthand notation for this page. The values can easily be assigned to a variable, e.g.,
x = 7
print(x)
7 -- output
= 7
7 -- output
Arithemetic expressions
Lua has the usual binary arithmetic operators.
= 2+3, 5-12, 2*7, 7/8
5 -7 14 0.875 --output
- Unary negation:
= -(-10), -(10)
10 -10
- Modulo (division remainder):
= 15%7, -4%3, 5.5%1
1 2 0.5
Control statement
Control structures let your program make choices, or to run the same piece of code many times.
if statement
The if statement lets you run different code based on a condition:
if condition then
block
elseif condition2 then
block
elseif condition3 then
block
else
block
end
The if and else if parts are checked in order, and once one of the conditions is true, it runs the block under it and skips to the end, ignoring any other else if conditions after it. The else block is run if none of the conditions matches. Finally, the else if and else parts are optional.
> n = 5
> if n > 5 then print("greater than 5") else print("less than 5") end
less than 5
> n = 7
> if n > 5 then print("greater than 5") else print("less than 5") end
greater than 5
For more complex example:
> n = 12
> if n > 15 then
>> print("the number is > 15")
>> elseif n > 10 then
>> print("the number is > 10")
>> elseif n > 5 then
>> print("the number is > 5")
>> else
>> print("the number is <= 5")
>> end
the number is > 10
You noticed how just one of the messages is printed, even though more than one of the conditions are true: This is because once one matches, the if statement skips checking the other conditions.
while loop
while condition do
block
end
This runs the block over and over in a loop on each iteration. It checks the conditions and if it's false, skips to the end and breaks the loop. If the condition is always false, the block will never run.
> i = 1
> while i <= 10 do
>> print(i)
>> i = i + 1
>> end
1
2
3
4
5
6
7
8
9
10
repeat loop
repeat
block
until condition
This is same as the while loop, except the condition is inverted(breaks the loop when true).
> i = 5
> repeat
>> print(i)
>> i = i - 1
>> until i == 0
5
4
3
2
1
Its checks after the first iteration, so the code is guaranteed to run at least once.
numeric for loop
for variable = start, stop, step do
block
end
Runs the block with a variable first being equal to start, then keeps incrementing it step amount and running the block again until it's greater than stop. step can be omitted and will default to 1.
You can also make the step negative, and the loop will stop once the counter variable is less than the stop value.
> for i = 1, 5 do
>> print(i)
>> end
1
2
3
4
5
> for i = 1, 100, 8 do
>> print(i)
>> end
1
9
17
25
33
41
49
57
65
73
81
89
97
> for i = 3, -3, -1 do
>> print(i)
>> end
3
2
1
0
-1
-2
-3
Also, remember that the variable in a for loop is only visible inside the block.
iterator for loop
for var1, var2, var3 in iterator do
block
end
The iterator version of the for loop takes a special iterator function and can have any amount of variables.What the loop does and how many variables it needs depends on the iterator. see example below:
> tbl = {"a", "b", "c"}
> for key, value in ipairs(tbl) do
>> print(key, value)
>> end
1 a
2 b
3 c
The ipairs is the iterator, which gets the numbered entries from a table in order.
break statement
The break statement causes Lua to jump out of the current loop:
> i = 3
> while true do -- infinite loop
>> print(i)
>> i = i + 1
>> if i > 6 then
>> break
>> end
>> end
3
4
5
6
With nested loops, break only affects the innermost one:
> for i = 1, 2 do
>> while true do
>> break
>> end
>> print(i)
>> end
1
2
Using break outside of a loop is a syntax error:
> break
stdin:1: <break> at line 1 not inside a loop
Conditions
Conditions don't necessarily have to be boolean values. In fact, any value is a valid condition: nil and false make the condition false, anything else (including 0) makes it true.
> if 5 then print("true") else print("false") end
true
> if 0 then print("true") else print("false") end
true
> if true then print("true") else print("false") end
true
> if {} then print("true") else print("false") end
true
> if "string" then print("true") else print("false") end
true
> if nil then print("true") else print("false") end
false
> if false then print("true") else print("false") end
false
In lua assignment is a statement and not an expression. See below example for syntax error:
> i = 0
> while (i = i + 1) <= 10 do print(i) end
stdin:1: ')' expected near '='
if/else as an expression
Lua doesn't have a ternary operator that acts like an if/else statement, but in many cases, you can imitate it using the and and or logical operators.This works for two reasons:
- Those operators don't even run the right-side expression if the logical result is known only from the left side result
- They directly return the result of their sub-expressions, instead of converting them to boolean:
> = true and print("test")
test
nil
> = false and print("test") -- 'and' is always false if one of the sides are false, don't bother running the other expression
false
> = true or print("test") -- 'or' is always true if one of the sides are true, don't bother running the other expression
true
> = false or print("test")
test
nil
> = 8 or 5
8
> = true and "text"
text
This can be used to make a simple if/else expression:
> condition = true
> = condition and 2 or 4
2
> condition = false
> = condition and 2 or 4
4
> = condition and print("a") or print("b") -- only the "false" branch is run, otherwise both a and b would be printed
b
nil
Also remember that and has a higher precedence than or. if the condition is false, it makes the and expression give up and return false.This then makes the or part try its right-side expression and return its value. If the condition is true, and will return its right-side expression. This is then given to or, which sees that the left result is a true condition, and just returns it.
Note that we assumed that the result of the true branch is a value that acts as a true condition. This leads to the catch: the true branch cannot evaluate to nil or false because then the false branch will also be run and its value will be returned:
> condition = true
> = condition and false or true -- wrong result!
true
This is because the whole "and" sub-expression is now false, causing "or" to try running its other sub-expression. But it is alright to return a false value from the false branch. In fact, if you're in a situation like the above example, you can just invert the condition and swap the contents of the branches:
> condition = true
> = not condition and true or false
false
But if both branches must return a value that acts as a false condition, there's no way to work around that.
Lua tables
Tables are the only "container" type in Lua.They are associative arrays, which means they store a set of key/value pairs. In a Key/Value pair you can store a value under a key and then later retrieve the value using that key.
Creating tables
Tables are created using table constructors, which are defined using curly brackets, e.g. { }. To define an empty table we can do the following.
> t = {} -- construct an empty table and assign it to variable "t"
> print(t)
table: 0035AE18
Notice when the value of a table is displayed only the type and unique id of the object are displayed. To print out the contents of a table we must do so explicitly.
Using tables
To access the value associated with the key in a table you can use the table[key] syntax:
> t = {}
> t["foo"] = 123 -- assign the value 123 to the key "foo" in the table
> t[3] = "bar" -- assign the value "bar" to the key 3 in the table
> = t["foo"]
123
> = t[3]
bar
if there's no value associated with the key, its not an error, instead the result will be nil:
> t = {}
> = t["foo"]
nil -- result is a nil not an error
You can erase a key/value pair from a table by assigning nil to the value.
> t["foo"] = nil
You can use any value can be used as a key (not just numbers and strings) just make sure it's not nil or NaN (Not a Number):
> t = {}
> k = {}
> f = function () end
> t[k] = 123
> t[f] = 456
> = t[k]
123
> = t[f]
456
> t[nil] = 123
stdin:1: table index is nil
stack traceback:
stdin:1: in main chunk
[C]: in ?
> t[0/0] = 123
stdin:1: table index is NaN
stack traceback:
stdin:1: in main chunk
[C]: in ?
It's so common to use string constants as keys there's a special shortcut syntax for it:
> t = {}
> t.foo = 123 -- same as t["foo"] (but not t[foo], which would use the variable foo as the key)
> = t.foo
123
> = t["foo"]
123
The shortcut syntax is only valid if the string consists of underscores, letters, and numbers, but shouldn't start with a number.
You can also add key/value associations right inside the {} syntax:
> t = {["foo"] = "bar", [123] = 456}
> = t.foo
bar
> = t[123]
456
There is also a syntax shortcut for string keys in {}, as long as the string conforms to the same rules as the . syntax:
> t = {foo = "bar"} -- same as ["foo"]="bar" (but not [foo]="bar" , that would use the variable foo)
> = t["foo"]
bar
To loop over all the key/value pairs in a table, use the pairs iterator:
> t = {foo = "bar", [123] = 456}
> for key,value in pairs(t) do print(key,value) end
foo bar
123 456
The order when looping with pairs is undefined. Just because you added one item after adding another doesn't mean that's the order they'll be in with pairs.
Inside a pairs loop, it's safe to reassign existing keys or remove them (by assigning nil to them), but not to add new keys (that had a nil value previously).
Tables as arrays
Tables are still just key/value containers because Lua doesn't actually have an array type. But tables can be treated like arrays which are explained here:
Table constructors can contain a comma-separated list of objects to create an "array":
> t = {"a", "b", "c"}
> = t[1]
a
> = t[3]
c
This is a syntax shortcut for:
> t = {[1]="a", [2]="b", [3]="c"}
> = t[1]
a
> = t[3]
c
Note it's still just a key/value association.
You can also mix the array syntax with the usual key=value syntax:
> t = {"a", "b", [123]="foo", "c", name="bar", "d", "e"}
> for k,v in pairs(t) do print(k,v) end
1 a
2 b
3 c
4 d
5 e
123 foo
name bar
The first index is the number one, unlike most other languages that start with the number zero. The reason this was chosen is that it's often more intuitive. It was also chosen because it's just a key and not an offset from the beginning.
You can get the "length" of an array using the # operator:
> t = {"a", "b", "c"}
> = #t
3
The # operator doesn't count all the items in the table (!). Instead, it finds the last integer (non-fractional number) key. Because of how it's implemented its results are undefined if all the integer keys in the table aren't consecutive. Which is why it shouldn't be used for tables used as sparse arrays).
There are two ways to add an item to the end of an array:
> t = {}
> table.insert(t, 123)
> t[#t+1] = 456
> = t[1]
123
> = t[2]
456
table.insert takes an optional index parameter to insert into the middle of an array. It shifts up any other integer keys above the index:
> t = {"a", "c"}
> table.insert(t, 2, "b")
> = t[1], t[2], t[3]
a b c
table.remove removes an item from an array, shifting down any remaining integer keys:
> t = {"a", "b", "c"}
> table.remove(t, 2)
> = t[1], t[2]
a c
To loop over an array use ipairs. Unlike pairs it only gives you the consecutive integer keys from 1. It guarantees their order sequence. With pairs the number keys will not necessarily be given in the correct order!
> t = {"a", "b", "c"}
> for i, v in ipairs(t) do print(i, v) end
1 a
2 b
3 c
To join together an array of strings there's table.concat. It takes an optional separator, starts, and end parameters. Here we only use the separator:
> t = {"a", "b", "c"}
> = table.concat(t, ";")
a;b;c
Table values are references
In lua when you pass a table to a function or store it in a new variable, etc. a new copy of that table is not created. Tables do not act like numbers in these cases. Instead, the variable or function becomes a reference to the original table.
> t = {}
> u = t
> u.foo = "bar"
> = t.foo
bar
> function f(x) x[1] = 2 end
> f(t)
> = u[1]
2
Tables are freed from memory by the garbage collector after the last reference to them is gone. This does not always happen immediately, however. The garbage collector is designed to work correctly even if a table (directly or indirectly) contains a reference to itself.
Comparing tables using == will return false even if the two tables have the same contents. They must actually be references to the same table. Table comparison works by reference.
If you want to copy a table you'll have to do it manually. Lua offers no standard function for it mainly due to all the different ways you can copy a table.
Tables as unordered sets
Often people new to Lua will create an array to store a group of objects even if the order isn't necessary. The problem with this is that removal is slow because the computer needs to shift down other items. Checking if an item is in the array is slow; again because the computer must loop over all the items.
This can be solved by storing items in the keys and setting values to a dummy value (like true). Doing that will help you use a table like an unordered set with fast insertion, removal, and lookup.
The main differences are that there's no easy way to get the count (you have to use a loop), and you can't store the same item twice in the set.
So if you need to store a group of items it's best to consider both sets and arrays to see what fits your situation best.
local items = {}
-- add some items to the set
items["foo"] = true
items[123] = true
-- is "foo" in the set?
if items["foo"] then
-- do stuff
end
-- remove item from the set
items[123] = nil