Lua is a script language developed in Brazil in the early 1990s. The Lua in­ter­pret­er trans­lates the source text of a Lua program into Bytecode and then executes it. The in­ter­pret­er itself is written in C, which gives Lua programs greater per­form­ance during execution. Moreover, the C-API allows Lua code to be embedded in C/C++ programs. Lua is a multi-paradigm language suitable for writing im­per­at­ive, func­tion­al, and object-oriented code.

Lua’s strongest dif­fer­en­ti­at­or is the simple embedding in other systems and languages. As a result, Lua has es­tab­lished itself as a “glue language” and is used in many game engines. What’s more, the language can be used to manage web servers like Apache and nginx. Via the CGI interface, Lua is also often used as a stand-alone internet pro­gram­ming language. In addition, the language is used for pro­gram­ming mobile apps.

Lua scripting tutorial: first steps

The easiest and fastest way to learn to program with Lua is to run Lua code on the in­ter­act­ive Lua demo website. You can test all the Lua code examples presented further on in this article. Copy one of the code examples into the text field and click on “run” to execute the code.

This means you don’t need to install anything. If you do wish to use Lua on your own system, follow our in­struc­tions below. Otherwise, skip to the section “Learning the basics of the Lua script language”.

Preparing your system for the Lua tutorial

The Lua in­ter­pret­er consists of a single binary file available in the command line after entering the command “lua”. This is saved to the system and may need to be entered in the pathway. Moreover, Lua offers libraries that enable the embedding of Lua code into C/C++ programs.

The “Homebrew” package manager can be used for in­stall­a­tion on Mac and Linux systems. If you have installed Homebrew on your system, enter the following in­struc­tion in the command line to install Lua:

brew install lua

To install Lua on a Windows system, you can turn to the LuaDist installer.

Using the Lua in­ter­pret­er in­ter­act­ively

As is the case with many script languages, the Lua in­ter­pret­er can be run in­ter­act­ively. In in­ter­act­ive mode, the in­ter­pret­er accepts Lua code in the command line and runs it line by line. The values generated in this way are output directly in the command line. As a user, you can then check and adjust the values of variables. This approach is therefore par­tic­u­larly suitable for rapid pro­to­typ­ing. To launch the Lua in­ter­pret­er in in­ter­act­ive mode, enter the following command in the command line:

# Start Lua interpreter in interactive mode
lua -i
Note

To leave in­ter­act­ive mode, input the command “os.exit()” or press the [Ctrl]+[D] keys together.

Running Lua script for the tutorial with the Lua in­ter­pret­er

Instead of entering Lua code piece by piece in the command line, you can also instruct the Lua in­ter­pret­er to run a complete Lua source text file. To do this, we first generate a Lua file and submit the file name to the Lua in­ter­pret­er for execution. The in­ter­pret­er then reads the source text contained in the file, line by line, and executes it.

# Run Lua script
lua <file name>.lua
Note

Lua source text files end with the file extension “.lua”.

Making Lua script for the tutorial directly ex­ecut­able using a hashbang

With the operating systems Linux / UNIX / macOS, we also can make a Lua source text file directly ex­ecut­able. Here, we enter a “hashbang” as the first line in the Lua file:

#!/usr/local/bin/lua
-- Lua code for execution

As you can see, the hashbang contains the storage location of the Lua binary file – in our example: #!/usr/local/bin/lua. In certain cir­cum­stances, the storage location may differ from this on your local system. In this case, you can find out the storage location of the Lua binary file by using the “which” command in the command line:

# Find out the storage location of the Lua binary file
which lua

After you have added the hashbang to a Lua script, you need to mark the file as ex­ecut­able for the user. Use the following command in the command line to this end:

# Mark Lua file as executable
chmod u+rx <file name>.lua

Then, run the Lua script in the current directory:

./<file name>.lua
Tip

The hashbang trick works with most script languages on Linux and UNIX-type systems such as macOS. The same approach allows you to make Ruby or Python scripts directly ex­ecut­able.

Learning the basics of the Lua script language

Lua is a multi-paradigm language. The fun­da­ment­al style is im­per­at­ive and func­tion­al. The language is com­pletely dynamic, i.e. no dis­tinc­tion is made between compile time and run time. Lua uses dynamic storage man­age­ment ex­clus­ively. The size of an object in the memory can change during run time. A “garbage collector” (GC) clears up any storage space that’s no longer needed, meaning pro­gram­mers do not need to take care of that them­selves.

Learning to use comments in Lua scripts

Comments are an essential part of any pro­gram­ming language. They are used for the following purposes among others:

  • Outlining code com­pon­ents
  • Doc­u­ment­ing code features
  • Ac­tiv­at­ing/de­ac­tiv­at­ing code lines

A single-line comment in Lua begins with a double hyphen (--) and runs until the end of the line:

-- this line is ignored by the interpreter

Multi-line comments can be written in com­bin­a­tion with double square brackets “[[” and “]]”:

--[[
This comment
covers multiple
lines.
]]

Values and types for the Lua coding tutorial

Like most other script languages, Lua is a dynamic type language. Types do not belong to variables, but values. Each value has exactly one type – whether it’s a number, string of char­ac­ters, truth value etc. Al­to­geth­er, Lua has a man­age­able number of types. They are sum­mar­ised in the following table:

Type Ex­plan­a­tion
number Decimal number
string Character string
boolean Truth value: “true” or “false”
nil Missing value; the type has only the value “nil”
function Function
table Combined data type: list/array, hash/dic­tion­ary
thread Coroutines
userdata User-defined C data type

Lua utilises literal syntax for values of all types, except for “thread” and “userdata”. To determine the type of a value, we use the “type()” function. This returns the name of the type as a string. Here’s a few examples:

type(42) -- Type is `number`
type("Lua Tutorial") -- Type is `string`
type(false) -- Type is `boolean`
type(var) -- Type is `nil`, because `var` is not defined
Note

With the following code examples, keep in mind that in Lua the first element of a list has the index 1 instead of 0, as is normally the case in most languages!

Learning to code with Lua: What are ex­pres­sions, variables, and operators?

An ex­pres­sion is evaluated by the in­ter­pret­er and a value is returned. Ex­pres­sions combine literals, operators, variables, and function calls. Ex­pres­sions can op­tion­ally be grouped with brackets “()”. Being a dynamic language, Lua auto­mat­ic­ally de­term­ines the type of the returned value. Here are some examples of ex­pres­sions:

-- Arithmetic operation in Lua
1 + 2 -- evaluates to the value `3`
-- String concatenation in Lua
'Walter' .. 'White' -- evaluates to `WalterWhite`
-- String concatenation with the automation conversion of a number in Lua
‘The ' .. 3 .. ' Musketeers' -- evaluates to `The 3 Musketeers`
-- Parity test in Lua
7 == '7' -- evaluates to `false`
-- Parity test in Lua
‘small' == string.lower(‘SMALL') -- evaluates to `true`
-- Dynamic type information
type(var) == 'nil' -- evaluates to `true`, because `var` is not defined

A variable is a name for a value in the memory. Like in most pro­gram­ming languages, a name in Lua starts with a letter or un­der­score (_), following by further letters, un­der­scores, or numbers. Here, a clear dis­tinc­tion is made between upper and lower case. The following reserved words may not be used alone as a name:

“and”, “end”, “in”, “repeat”, “break”, “false”, “local”, “return”, “do”, “for”, “nil”, “then”, “else”, “function”, “not”, “true”, “elseif”, “if”, “or”, “until”, “while”

However, the reserved words can appear as part of a name without causing any problems:

for = "Peter" -- produces an error
for_user = "Peter" -- allowed

A value is assigned to a variable using the as­sign­ment operator (=). This shouldn’t be confused with the logical parity operator (==). As normal, a dis­tinc­tion is made in as­sign­ment between “L” value and “R” value. The variable has to be on the left side of the as­sign­ment operator, i.e. it is the L value. This is assigned the evaluated value of the R value on the right:

number = 13 -- this is OK
13 = number -- produces an error, because the number 13 cannot be assigned a new value

An operator generates a new value from one or more operands. Here, we refer to a unary (one-digit) or binary (two-digit) operator. An operator combines operands of a certain type and returns a value of a certain type. Let’s look at the different operators in Lua.

Arith­met­ic operators work with numbers and return a number:

Arith­met­ic operator Arity Operation
+ Binary Addition
- Binary Sub­trac­tion
* Binary Mul­ti­plic­a­tion
/ Binary Division
% Binary Modulus
^ Binary Po­ten­ti­ation
- Unary Negation

The re­la­tion­al operators are all binary, and they test how two operands relate to each other. They return a truth value:

Re­la­tion­al operator Test
== Parity
~= Non-parity
> Larger than
< Smaller than
>= Larger than or equal to
<= Smaller than or equal to

Logical operators combine truth values and return a new truth value:

Logical operator Arity Operation
and Binary AND com­bin­a­tion
or Binary OR com­bin­a­tion
not Unary Negation

In addition to the operators above, there are two special operators in Lua. These are used to con­cat­en­ate strings and determine the power of a combined value, like a table or string:

Operator Arity Operation
.. Binary String con­cat­en­a­tion
# Unary Determine the number of elements of a table / length of a string

Lua does not use any combined al­loc­a­tion operators like “+=” and “-=”, which can usually be found in many script languages. For in­cre­ment­ing and decre­ment­ing variables, the operation is written out ex­pli­citly:

price = 42.99
discount = 0.15 -- 15% discount
price -= price * discount -- `-=` does not work in Lua
-- Decrementation must instead be written out explicitly
price = price - (price * discount)

Un­der­stand­ing validity ranges and blocks for the Lua pro­gram­ming tutorial

The concept of the validity range is important for any pro­gram­ming language. A variable only exists within a certain valid range. Like in JavaS­cript, variables in Lua are global by default. However, the con­tinu­ous use of global variables is known as “anti-patterns” and should be avoided. In Lua, a solution can be found in the form of the “local” keyword. This allows you to limit the validity range of a variable to the sur­round­ing block – com­par­able to the de­clar­a­tion via “let” in JavaS­cript.

-- This variable is global
x = 5
-- Define a local variable
local z = 10

The bodies of functions and loops open a new validity range in Lua. Moreover, Lua uses the concept of the explicit block. A block defines a new validity range for the code between the keywords “do” and “end”. This cor­res­ponds to the open/closing brackets “{” and “}” in Java/C/C++. The following code example shows how blocks, validity ranges, and variables relate to each other:

-- Outer validity range
do
    local x = 1
    do -- inner validity range
        local y = 2
        -- Generate `z` in the global validity range
        -- access local variable `x` from the outer validity range
        -- and local variable `y` from the inner validity range
        z = x + y -- `z` now has the value `3`
    end
    print(x) -- outputs `1`
    print(y) -- outputs `nil`, because `y` does not exist in the outer validity range
    print(z) -- outputs `3`
end
-- `z` is global, i.e. it exists outside the outer validity range
z = z + 4
print(z) -- outputs `7`

Learning to program with the Lua control struc­tures

Lua offers the normal control struc­tures that can also be found in other pro­gram­ming languages. These include branches and loops. Here’s an example of Lua’s “if”, “then”, “else”, and “elseif” in­struc­tions:

limit = 42;
number = 43;
if number < limit then
    print("Under the limit.")
elseif number == limit then
    print("Right on the limit…")
else
    print("Over the limit!")
end

Besides the classic “while” loop, Lua also re­cog­nizes its coun­ter­part “repeat” “until”. This in­struc­tion can also be found in Ruby. It requires a reversal of the condition used. That means, a “while” with the condition “number </= limit” cor­res­ponds to a “repeat” “until” with the condition “number > limit”. Beware when using the “repeat” in­struc­tion! Re­gard­less of the condition, the loop body is executed at least once. Here’s an example:

limit = 10
number = 1
while number <= limit do
    print("Number:", number)
    number = number + 1
end
-- Attention: although `number` is already larger than `limit`
-- the loop body is executed once
number = 11
repeat 
    print("Number:", number)
    number = number + 1
until number > limit

Like most im­per­at­ive pro­gram­ming languages, Lua offers a “for” in­struc­tion in addition to the “while” loop. Two variants are used: a C-like variant with a loop variable as well as a variant with an iterator. Let’s first consider the use of the “for” in­struc­tion with the loop variable:

start = 1
end = 10
for number = start, end do
    print("Current number:", number) -- `1,2,3,4,5,6,7,8,9,10`
end
-- Explicitly set step to `2`
step = 2
for number = start, end, step do
    print("Current number:", number) -- `1,3,5,7,9`
end
-- the step can also be negative
step = -2
-- With a negative step, swap start and end to count in descending order
for number = end, start, step do
    print("Current number:", number) -- `10,8,6,4,2`
end

Sur­pris­ingly, the loop variable defined in the “for” loop is local, not global, without it having to be ex­pli­citly declared as local. This makes sense and, in this respect, Lua differs pos­it­ively from JavaS­cript. There, a loop variable declared without “let” or “var” is global, which can lead to severe errors.

Now we can move on to Lua’s “for” loop with an iterator. In principle, the approach is like Python. Instead of in­cre­ment­ing a loop variable and using it as an index in a list, we iterate directly using the elements of the list. The “ipairs()” function is often used to generate the iterator. Here’s an example:

-- Define list of years
decades = {1910, 1920, 1930, 1940, 1950, 1960, 1970, 1980, 1990}
-- Access the individual years using an iterator
for index, year in ipairs(decades) do
    print(index, year)
end

Learning more about functions with Lua

As is the case in C/C++, Java and JavaS­cript, functions are defined with the “function” keyword. The function para­met­ers are written in brackets after the function names. With Lua, however, the brackets can be left out for a function call with exactly one literal as a parameter. A Lua function does not ne­ces­sar­ily have to return a value. According to the defin­i­tion, a function without a value is a “procedure”:

-- Define procedure
function hello(name)
    print("Hello", name)
end
-- Call function
hello("good sir")
-- this is also possible
hello "good sir"
-- the following will not work, however
name = "Walter"
hello name -- syntax error
-- with a variable instead of a literal, the function must be called with brackets
hello(name)

If you want to return a value from a function, the “return” keyword is used as normal. This ends execution of the function and returns the entered value. In the following code example, a number is squared:

-- Function with a single return value
function square(number)
    -- the expression `number * number` is evaluated
    -- and its value returned
    return number * number
end
-- Square number
print(square(9)) -- `81`

Like in Python and JavaS­cript, a function in Lua can accept a variable number of para­met­ers. The para­met­ers are stored in the special construct “(...)”. To access the para­met­ers, it’s often useful to summarise them in a list with the ex­pres­sion “{...}”. Al­tern­at­ively, you can use the “select{}” function to extract a parameter under the entered index. We can determine the number of para­met­ers with the ex­pres­sion “#{...}”.

-- Print all parameters of a function
function var_args(...)
    for index, arg    in ipairs({...}) do
        print(index, arg)
    end
end
var_args('Peter', 42, true)

Besides the variable number of para­met­ers, Lua also permits returning multiple values with a “return” in­struc­tion. This works similar to Python, but without the explicit “tuple” type. Like in Python, it’s normal to assign multiple variables to the return value for the function call. Here’s an example:

-- Function with multiple return values
function first_and_last(list)
    -- return first and last element of the list
    individual return values are separated by a comma `,`
    return list[1], list[#list]
end
people = {"Jim", "Jack", "John"}
-- Assignment of return values to multiple variables
first, last = first_and_last(people)
print("The first is", first)
print("The last is", last)

If one of the return values is not required, you can use the un­der­score (_) as a place­hold­er, following common con­ven­tion, as shown in the following example:

function min_mean_max(...)
    -- Set initial values for `min` and `max` to the first parameter
    local min = select(1, ...)
    local max = select(1, ...)
    -- Initially set mean value to nil 
    local mean = 0
    -- Iterate using the numbers
    -- We do not need the index variable
    -- and therefore use `_` as a placeholder
    for _, number    in ipairs({...}) do
        -- Set a new minimum if necessary
        if min > number then
            min = number
        end
        -- Set a new maximum if necessary
        if max < number then
            max = number
        end
        -- Sum the numbers to find the average
        mean = mean + number
    end
    -- Divide the numbers by their quantity
    mean = mean / #{...}
    return min, mean, max
end
-- Here we do not need the `mean` value
-- and therefore use `_` as a placeholder
min, _, max = min_man_max(78, 34, 91, 7, 28)
print("Minimum and maximum of the numbers are", min, max)

In Lua, functions are “first-class citizens”. In other words, they can be bound to variables and can therefore also be trans­ferred to other functions as para­met­ers. What’s more, a function can act as a return value of a function. Overall, Lua thus enables func­tion­al pro­gram­ming – shown here using the well-known “map()” function as an example:

-- `map()` function in Lua
-- Accepts a function `f` and a list as parameters
function map(f, list)
    -- Create new list for output values
    local _list = {}
    -- Iterate using the elements of the list with an index
    for index, value in ipairs(list) do
        -- Apply function `f()` to the current value of the list
        -- and save the return value in a new list on the same index
        _list[index] = f(value)
    end
    -- Return new list
    return _list
end
-- List of numbers
numbers = {3, 4, 5}
-- Function applied to all elements of the list
function square(number)
    return number * number
end
-- Generate the squares via the `map()` function
squares = map(square, numbers) -- `{9, 16, 25}`
-- Output squared numbers
for _, number in ipairs(squares) do
    print(number)
end

Recursion is often used in func­tion­al pro­gram­ming. A function calls itself re­peatedly with modified para­met­ers. Here we need to exercise special caution in Lua. Functions that are accessed re­curs­ively should be declared ex­pli­citly as “local”.

function f()
    -- Recursive call
    f() -- may refer to the global variable `f`
end
-- instead
local function f()
    -- Recursive call
    f() -- refers to the local function
end
-- equivalent to
local f; -- Declare variable `f` explicitly as `local`
f = function() -- Assignment of the function to the local variable `f`
    f() -- is guaranteed to refer to the local function
end
Go to Main Menu