Lua in 60 minutes

Lua? What does it stand for?

Lua is a simple built-in language (it can be integrated with your applications created in other programming languages), easy-to-understand and comprehensive, with the only data type, and uniform syntax. It seems to be an ideal language for mastering. 

What for?

Lua will be useful for you:

  • In case you are a gamer (plug-ins for World of Warcraft and many other games)

  • In case you write games (quite often, the games’ engine is written in C/C++, and AI – in Lua)

  • In case you are a system developer (you can create plugins for nmap, Wireshark, nginx and other utilities on Lua)

  • In case you are an embedded developer (Lua is very fast, compact and requires very few resources)

What is necessary in order to read further?

1. Learn to code, at least a little. No matter what programming language, you just need to understand the basic principles.

2. Download and install Lua. In order to accomplish this, you should either download version 5.2 here (http://www.lua.org/download.html) or look for it in the repositories. Version 5.1 also works, but you should understand that is pretty old.


You need to run all the examples from the article in a terminal with a command like “Lua file.lua”.

First impressions

Lua is a dynamically typed language (variables get types on runtime depending on the assigned values). Using Lua, you follow an imperative, an object-oriented, or functional style (in case you do not know what does it mean – just go on, we will tell you). Here is the Hello world on Lua:


– my first Lua app: hello.lua

print “hello world”;

print (“goodbye world”)



What can we say about the language right now:

  • single-line comments begin with two hyphens “–“

  • brackets and dot-commas are optional.

Language operators

The set of conditional statements and loops is fairly typical:


– conditional operators (else branches may not be)

if a == 0 then

  print (“a is zero”)


  print (“a is not zero”)



– abbreviated form if / elseif / end (instead of switch / case)

if a == 0 then

  print (“zero”)

elseif a == 1 then

  print (“one”)

elseif a == 2 then

  print (“two”)


  print (“other”)



– cycle with counter

for i = 1, 10 do

  print (i)



– cycle with precondition

b = 5

while b> 0 do

  b = b – 1



– cycle with postcondition


  b = b + 1

until b> = 5

THINK: what can the loop “for i = 1, 10, 2 do … end” mean?


In expressions, you can use the following operators over variables:


  • assignment: x = 0

  • arithmetic: +, -, *, /,% (remainder of division), ^ (exponentiation)

  • logical: and, or, not

  • comparison:>, <, ==, <=,> =, ~ = (not-equal, yes, yes, instead of the usual “! =”)

  • string concatenation (operator “..”), eg: s1 = “hello”; s2 = “world”; s3 = s1..s2

  • length / size (operator #): s = “hello”; a = #s (‘a’ will be equal to 5).

  • getting item by index, eg: s [2]


There were no bit operations in the language for a long time, but in version 5.2 a bit32 library appeared that implements them (as functions, not as operators).

Data types

Actually, Lua has many data types as any solid programming language:


  • nil (absolutely nothing)

  • boolean numbers (true / false)

  • numbers (numbers) – without division into integer / real numbers. Just numbers.

  • strings – by the way, they are very similar to the strings in Pascal

  • functions – yes, the variable may be of the type “function”

  • thread

  • arbitrary data (userdata)

  • table


If everything is clear with the first types, then what is userdata? Recall that Lua is an embedded language, and usually works closely with program components written in other languages. So, these “alien” components can create data to fit their needs and store this data together with lua-objects. So, userdata is the underwater part of the iceberg, which is not necessary from the point of view of the Lua language, but we simply cannot ignore it.


And now the most important thing in the language – tables.



There is the only data type in Lua and it is connected with tables. A table is a very elegant data structure, it combines the properties of an array, a hash table (“key” – “value”), structure, object.


– So, here is an example of a table as an array:

a = {1, 2, 3} – an array of 3 elements

print (a [2]) – will print “2” because indices are counted from one

– A table in the form of a sparse array (which does not have all the elements)

a = {} – empty table

a [1] = 1

a [3] = 5

THINK: what is a [2] equal to in the case of a sparse array?


In the example above, the table behaves like an array, but in fact – we have keys (indices) and values ​​(array elements). And at the same time, any types can be keys, not just numbers:


a = {}

a [“hello”] = true

a [“world”] = false

a [true] = 1

– or so:

a = {

  hello = 123,

  world = 456


print (a [“hello”))

print (a.hello) is the same as a [“hello”], although it looks like a structure with fields


By the way, since the table has keys and values, it is possible to cycle through all the keys and the corresponding values:


t = 

  a = 3,

  b = 4


for key, value in pairs (t) do

  print (key, value) – displays “a 3”, then “b 4”



What about the objects? We will learn about them a little later, first about functions.


Here is an example of a regular function.


function add (a, b)

  return a + b



print (add (5, 3)) – prints “8”


The language functions allow you to take multiple arguments, and return multiple arguments. So the arguments, the values of which are not specified explicitly, are considered to be equal to nil.

THINK: why might you need to return several arguments?


function swap(a, b)

  return b, a



x, y = swap(x, y)

— by the way, you can do it without a function:

x, y = y, x

— if the function still returns several arguments

— and you do not need them – ignore them with the help of 

— a special variable “_”

a, _, _, d = some_function()


Functions can take a variable number of arguments:


— in a prototype, different numbers of arguments is written as ellipsis

function sum(…) 

   s = 0

   for _, n in pairs(arg) do — we look into it inside the function, as to “arg” table

      s = s + n


   return a



sum(1, 2, 3) — will return 6

sum(1, 2, 3, 4) — will return 10

Since functions are a full-fledged data type, variable functions can be created, and functions can be passed as arguments to other functions.


a = function(x) return x * 2 end — the function which multiplies by 2

b = function(x) return x + 1 end — the function which increases by 1


function apply(table, f)

  result = {}

  for k, v in pairs(table) do

    result[k] = f(v) — replacing the elemnt with a particular function from this element




— THINK: what the calls will return

t = {1, 3, 5}

apply(t, a)

apply(t, b)


Objects = functions + tables


Since we can save functions in variables, we can also in the fields of the tables. And it already turns out how-to-methods. For those who are not familiar with OOP, I will say that its main benefit (at least in Lua) is that the functions and data with which they work are close – within the same object. For those who are familiar with OOP, I will say that there are no classes here, but prototype inheritance.


Let us turn to examples. We have an object, say, a light bulb. She knows how to burn and not burn. Well, you can do two actions with it – turn it on and off:


lamp = 

  on = false

function turn_on (l)

  l. on = true



function turn_off (l)

  l. on = false



– these are just functions for working with the structure.

turn_on (lamp)

turn_off (lamp)


And if the light bulb is made an object, and the turn_off and turn_on functions are made the fields of an object, you get:


lamp = 

  on = false

  turn_on = function (l) l.on = true end

  turn_off = function (l) l.on = false end


lamp. turn_on (lamp)

lamp. turn_off (lamp)


We have to pass the light bulb object itself as the first argument, because otherwise, our function will not know which light bulb to work with so as to change the on and off condition. But in order not to be verbose, there is an abbreviated admittance in Lua, which is usually utilised by lamp: turn_on (). So we already know several such syntax simplifications:


light: turn_on () – the most prevalent admittance

light. turn_on (lamp) – from the purpose of view of format, this is also correct

lamp [“turn_on”] (lamp) – which

Ongoing to mention abbreviations, functions can be described not only explicitly, as construction fields, but additionally in a more convenient form:


lamp = {

  on = false


– through the purpose, then the argument must be specified

function light. turn_on (l) d. on = true end


– through colons, then your debate is implicitly established by itself, because of the variable “self”

– “self” is the sunshine bulb for which the technique was called.

function lamp: turn_off () self. on = false finish


Special features

Some names of functions of dining tables (methods) are appropriated, found a special meaning:


  • __add (a, b), __sub (a, b), __div (a, b), __mul (a, b), __mod (a, b), __pow (a, b) – are called when arithmetic businesses are performed on desk

  • __ unm (a) – unary function “minus” (when they write something similar to “x = -x”)

  • __lt (a, b), __le (a, b), __eq (a, b) – estimate the result of the comparison ( <,  <=, ==)

  • __len (a) – called when done “#a”

  • __concat (a, b) – called when “a.. b”

  • __call (a,… ) – called when “a ()”. Variable arguments are the arguments to the call.

  • __index (a, i) – referring to [i], provided that there is absolutely no such element

  • __newindex (a, i, v) – create “a [i] = v”

  • __gc (a) – when the thing is deleted during garbage collection


Replacing these methods, you can overload the operators and use the syntax of the language for their own purposes. The main thing is not to overdo it.



For those who do not know the OOP, inheritance enables you to extend the functionality of the already existing class. For instance, simply a light bulb can turn on and off, and the super-light will also change its brightness. Why do we need to rewrite turn_on / turn_off methods if we can reuse them?

In Lua, for this there is the concept of a meta-table, i. e. ancestor tables. Each table has one ancestor table, and a child table can do everything that an ancestor can do.


Assume that the table object lamp has already been created. Then the super-light will look like this:


superlamp = {

  brightness = 100


— we specify the parent table

setmetatable (superlamp, lamp)

— and its methods are now available.

superlamp: turn_on ()

superlamp: turn_off ()


Expansion of functionality

Many types have parent tables (well, rows and tables are exact, numbers and boolean numbers, and nil do not have them). Suppose we want to add all the lines using the operator “+”, and not “.. “. To do this, change the function “+” (__add) for the parent table of all rows:


s = getmetatable (“”) – get the parent table of the row

s. __ add = function (s1, s2) return s1.. s2 finish – changed the method


– we check

a = “hello”

b = “world”

print (a + b) – will write “helloworld”

Actually, we can still replace the print function by using “print = myfunction”, and many other hacker cases can be done.


Variables are global and local. When created, all variables in Lua are global.


THINK: why?


To specify the local scope, write the keyword local:


local x

local var1, var2 = 5, 3


Do not forget about this word.

Error processing

Often, if errors occur, it is necessary to stop the execution of a particular function. You can, of course, do a lot of checks and call “return” if something went wrong. But it will boost the amount of code. In Lua, something like exceptions is used.


Errors are produced using the error (x) function. Anything can be passed as an argument (what is relevant to the error is a string description, a numeric code, an object with which the error occurred, etc. )


Usually, after this function, the whole program crashes. Plus this is not at all times necessary. If you call functionality that can create an error (or its child functions can create an error), then call it safely using pcall():


functionality f (x, y)

  if… then

    error (“failed to do something”)




status, err sama dengan pcall (f, by, y) – farrenheit: function, x-y: the arguments

 If not status then

— process err error. In our situation, err is the error text.


Standard Libraries

You will find few standard your local library, but this allows you to definitely run Lua anywhere. For more information, you can get a set of them here – http://www.lua.org/manual/5.2/manual.html

There are many non-standard your local library, they can be available on LuaForge, LuaRocks and other repositories.

Between Lua and Non-Lua

ATTENTION: this part is suggested to be read by people with knowledge of Chemical.


If the functionality of standard libraries is not enough for all of us? Whenever we have our C program, and we want to call its functions from Lua? Presently there is a very simple mechanism for this.


Suppose we would like to create our own function that earnings a random quantity (in Lua there is math. arbitrary (), but we want to learn). We are going to have to write such Chemical code here:


#include  <lua. h>

#include  <lauxlib. h>

#include  <time. h>


or * actually, what to do when calling `rand (from, to)` * or

static int librand_rand (lua_State * L) 

    int from, to;

    int x;


    from = lua_tonumber (L, 1); / * first function parameter * /

    to = lua_tonumber (L, 2); / * second function parameter * /


    x = rand ()% (to – from + 1) + from;


    lua_pushnumber (L, x); / * return value * /

    return 1; / * return only one argument * /

/ 2. in Lua “rand” corresponds to our librand_rand () functionality * or

stationary const luaL_reg L [] = 

    “rand”, librand_rand,

    NULL, NULL / *   conclusion of the   set of exported functions * /



or * called when loading the collection * or

LUALIB_API int luaopen_librand (lua_State * L) 

    luaL_openlib (L, “librand”, R, 0);

    srand (time (NULL));

    return 1; / * succeed * /

Thus, Lua provides us with functions for working with data types, getting arguments from functions and returning results. There are extremely few functions and they are fairly simple. Now we build our library as dynamic, and we can use the rand() function:


random = require (“librand”) – load the library


print (random. rand (1, 100))

print (random. rand (0, 1))


And if we want to call code written in Lua from our programs? Then our programs should create a Lua virtual machine in which Lua scripts will be executed. It is much easier:


#include “lua. h”

#include “lauxlib. h”


int main () {in front

   lua_State *L = lua_open(); // creating local machine Lua

    luaL_openlibs(L); // downloading the standard library     luaL_dofile(L, “rand.lua”); // running the script

    lua_close(L); // closing Lua

    return 0;

Here you are!

Now you can code in Lua! We believe this article will be useful for you and will help you come with Lua effortlessly. 

Leave a Comment