Lua Tutorial

What is Lua?

From wikipedia:

Lua ( /ˈluː.ə/ LOO-ə) is a lightweight, reflective, imperative and functional programming language, designed as a scripting language with extensible semantics as a primary goal. The name comes from the Portuguese word lua meaning “moon”.

What’s the difference between a static language (like C or C++) and a dynamic language like Lua?

Dynamic programming language is a term used broadly in computer science to describe a class of high-level programming languages that execute at runtime many common behaviors that other languages might perform during compilation, if at all. (wikipedia)

For example, where a variable in C has a type bound to it which cannot change (static typing), a variable in Lua is just a name under which any type of value can be stored. (In a way, all variables in Lua behave like pointers.) More interestingly, any string of valid Lua code can be executed from within another script; opening the possibilty of generating new functions at run-time. Data structures can change size and layout during execution, and functions can be passed around just like any other object, all according to the vagaries of user input. (Some of these features are possible in C/C++ with a lot of clever coding, but the cleverer that code gets, the more it becomes like the virual machine of an interpreted langauge anyway…)

What’s exciting about Lua?

Fast (one of the fastest dynamic languages). “Several benchmarks show Lua as the fastest language in the realm of interpreted scripting languages.” For this reason in particular, it is perhaps most widely used for game scripting. In addition, the LuaJIT project uses a trace compiler to convert hot code paths and loops into i386 or x86_64 machine code, with performance often on par with C/C++.

Expressive. Lua began as a data-description language, and continues to benefit from a universal and flexible array/hash data structure. The syntax is largely procedural, however it supports fully functional programming features such as first-class functions, closures and coroutines, and lexically scoped upvalues (granting capabilities similar to Scheme). It also supports various models of inheritence through a prototype inheritence chain (similar to Self and JavaScript). The runtime is also fully re-entrant.

Easy to learn. Really, the majority of the language’s grammar/syntax/typical usage can be learned in one day.

Extensible. These expressive features, plus a dynamic library module system (binary or Lua code) make it easy to extend Lua for a particular project or task.

Small. Lua as a static library is just a few hundred K, making it ideal for embedding within a host program.

Simpler C API. The simplicity of binding Lua to C code is often mentioned as a key attraction of Lua (as opposed to alternative embeddable langauges such as Python andRuby).

Portability. The Lua core is ANSI C compliant: that means it should run on almost any system these days. A lot of effort is currently going into improving Lua on microcontrollers.

Lua is licensed under the MIT license, so there are basically no restrictions on embedding, deriving or modifying it.

What’s not so exciting?

Limited set of standard libraries. Compared to Perl or Python, Lua has very few built-in libraries, and a reasonable but not outstanding set of third-party libraries. The chances of your favourite C library being bound to Lua are much less…

No built-in threading. Deterministic multi-tasking is fully supported using coroutines, but if you want to make use of your processors, you need to make use of third party libraries that might not always be so stable.

Array indexing starts from 1. A feature inherited from its background in data-description, but a gotcha for programmers coming from a background in C…

Documentation and Resources

Programming in Lua

This book is *excellent*. Get it from here:

Programming in Lua (second edition)
by Roberto Ierusalimschy
Lua.org, March 2006
ISBN 85-903798-2-5 (also available as an e-book)

Programming in Lua is also available in German, Korean, Chinese, and Japanese.

The Lua 5.1 Reference Manual

Another excellent resource. Fortunately, it is available online: http://www.lua.org/manual/5.1/.

Lua 5.1 Reference Manual
by R. Ierusalimschy, L. H. de Figueiredo, W. Celes
Lua.org, August 2006
ISBN 85-903798-3-3

In particular, this is the URL that should be bookmarked: http://www.lua.org/manual/5.1/index.html#index

The lua-l Mailing List

http://vlists.pepperfish.net/cgi-bin/mailman/listinfo/lua-l-lists.lua.org

Archive here: http://lua-users.org/lists/lua-l/

Quite a diversity of low to high level discussion, but 500-1000 messages per month!

Lua Wiki

Some tutorials here: http://lua-users.org/wiki/TutorialDirectory

This unofficial FAQ may also be useful: Steve Donovan’s unofficial Lua FAQ

The Lua Language

Hello World

--[[ this is a multi-line comment--]]
-- this is a single-line comment

print("hello world")

Basic Types

All values in Lua are one of the following types; however unlike C, the type does not belong to the variable, but to the value itself. That means that a variable can change type (dynamic typing).

Numbers

All numbers in Lua are 64-bit floating point type (aka ‘double’ for C programmers). There is no distinction between integers and non-integers.

-- these lines are all equivalent:
-- they assign the number value 1 to the variable name x:
x = 1
x = 1.0
x = 100e-2  -- e base10 format
x = 0x1 --hexadecimal format

Strings

Lua strings are immutable: each string operation creates a new string. (strings are hashed internally very efficiently, and garbage collected).

print("a simple string")
print('a simple string')

-- embedding special characters and multi-line strings:
x = "a string isn't stopped by \n a new line";
x = 'a string isn\'t stopped by \n a new line'
x = [[a string isn't stopped by
a new line]]

Boolean and nil

Boolean values are the keywords true and false. The nil value indicates the absence of a value. Assigning nil to a variable effectively marks the variable for garbage collection.

t = true
f = false
n = nil

-- nil evaluates to false for a predicate:
if t then print("t!") end -- prints t!
if f then print("f!") end -- prints nothing
if n then print("n!") end -- prints nothing

Tables

Table is the only structural type in Lua: all data structures are made from tables, and even a large part of Lua’s own implementation relies upon them.

Tables in Lua are associative arrays, mapping keys to values. Both keys and values can be any valid Lua type except nil (booleans, numbers, strings, other tables (or even the same table!), functions, coroutines and so on.)

local t = {}  -- empty table constructor
t[1] = "one"  -- assignment
t["two"] = 2  -- keys and values can be any types
t[true] = function() print("true!") end

-- except nil:
t[x] = nil  -- removes t[x] reference
t[nil] = 1  -- error!
In particular, string key lookup on a table has a useful short-hand form:

local t = {}  -- empty table constructor
t[1] = "one"  -- assignment
t["two"] = 2  -- keys and values can be any types
t[true] = function() print("true!") end

-- except nil:
t[x] = nil  -- removes t[x] reference
t[nil] = 1  -- error!

It’s important to note that a Lua table has two parts; an array portion and a hashtable portion. The array portion is indexed with integer keys, starting from 1 upwards while the integer keys are contiguous. All other keys are stored in the hash (or record) portion.

Array Portion

The array portion gives Lua tables the capability to act as ordered lists, and can grow/shrink as needed (similar to C++ vectors). Sometimes the array portion is called the list portion, because it is useful for creating lists similarly to LISP. In particular, the table constructor will insert numeric keys in order for any values that are not explicitly keyed:

-- these two lines are equivalent
local mylist = { [1]="foo", [2]="bar", [3]="baz" }:
local mylist = { "foo", "bar", "baz" }

print(mylist[2]) -- prints bar

To walk over every key/value in the table, there is the pairs form. Note however, that the order of traversal cannot be predicted:

local t = { "foo", "bar", x = 1, y = 2 }
for key, value in pairs(t) do
  print(key, value) -- prints all keys and values
end

Functions

Unlike C, functions are first-class values, just like numbers, strings and tables. That means that functions can be keys and values in tables, functions can take functions as arguments, and return functions as return values. This might seem exotic at first, but can be very valuable.

A simple function:

-- these are equivalent:
sayhello = function(message)
  print("hello", message)
end

function sayhello(message)
  print("hello", message)
end

-- using the function:
sayhello("me")  -- prints: hello me
sayhello("you") -- prints: hello you

-- replacing the function
sayhello = function(message)
  print("hi", message)
end

sayhello("me")  -- prints: hi me

Of course, a function can have more than one argument… but it can also have more than one return value:

function minmax(a, b)
  return math.min(a, b), math.max(a, b)
end
print(minmax(42, 13)) -- prints: 13 14

A special syntax is available for a table’s member functions that are intended to be used as methods. The use of a colon (:) instead of a period (.) to index the table passes the table itself through as a special ‘hidden’ variable self (similar to the hidden variable this in C++).

local t = { value = 10 }

-- define a method:
t.printvalue = function(self)
  print(self.value)
end

-- equivalent:
function t:printvalue()
  print(self.value)
end

-- use the method:
t.printvalue(t) -- prints: 10

-- equivalent:
t:printvalue()  -- prints: 10

Control Flow

Lua includes a standard set of control flow structures.

-- if blocks:

if x == 1 then
  print("one")
  -- as many elseifs as desired can be chained
elseif x == 2 then
  print("two")
elseif x == 3 then
  print("three")
else
  print("many")
end

-- while loops:
x = 10
while x > 0 do
  print(x)
  x = x - 1
end

repeat
  print(x)
  x = x + 1
until x == 10

Logical Operators

  • Equals: ==
  • Not-equals: ~=
  • Comparatives: < <= >= >
  • Logical combinators: and or not
if x > 12 and x <= 20 then print("teen") end

Variables and Scoping

Variable names in Lua can be any string of letters, digits, and underscores, not beginning with a digit (the same as most other languages). Some names are reserved in the language itself, including:

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

Local and global; lexical scoping

New identifiers (variables) can be defined to be local to a particular block (code chunk), or global. Defining an identifier as local is done using the local keyword. Local identifiers are not visible outside the block in which they were declared, but are visible inside sub-blocks. This is called lexical scoping.

function foo(x)
  -- a function body is a new block
  local y = "mylocal"
  if x == y then
    -- this is a sub-block of the function
    -- y is still visible here
    print(y)  -- prints: mylocal
  end
end
-- y is not visible here:
print(y)    -- prints: nil

Assigning to a variable that has not been declared locally within the current block will search for that name in parent blocks, recursively, up to the top-level. If the name is found, the assignment is made to that variable. If the name is not found, the assignment becomes a global (either creating a new variable, or replacing an existing global). Global identifiers are stored in the implict globals table, which can be explicitly accessed through the name _G.

-- an outer variable:
local x = "outside"
print(x) -- prints: outside

-- sub-block uses a local, which does not affect the outer variable:

function safe()
  local x = "inside"
end
safe()
print(x) -- prints: outside

-- sub-block does not use a local, and overwrites the outer variable:
function unsafe()
  x = "inside"
end
unsafe()
print(x) -- prints: inside

It is good practice to make as many variables local as possible since it greatly improves performance. More importantly, unexpected assignment to non-local variables is probably the most common cause of Lua scripting errors!

Garbage Collection

Objects are never explicitly deleted in Lua (though sometimes resources such as files might have explicit close() methods). Lua has an fast incremental garbage collector that runs in the background, which silently recycles the memory for any values to which no more references remain. For most built-in types (strings, tables etc) this need never concern us. When binding C/C++ objects as full userdata types, the garbage collect event can be handled through a special metamethod.

Going Deeper

Higher Order Functions

Functions as return values:

function operate(operator)
  if operator == "add" then
    return function(a, b)
      return a + b
    end
  elseif operator == "mul" then
    return function(a, b)
      return a * b
    end
  end -- end if
end -- end function operate

local f = operate("mul")
f(2, 10) -- prints: 20

Functions as table values:

local t = {
  add = function(a, b)
    return a + b
  end,
  mul = function(a, b)
    return a + b
  end,
}

t.mul(2, 10) -- prints: 20

In fact, when a function is declared as a global variable, it is in fact just an assignment to an implicit globals table. This table can be explicitly accessed using the special name _G:

-- these are all equivalent:
function foo() print("foo") end
foo = function() print("foo") end
_G.foo = function() print("foo") end

_G["foo"] = function() print("foo") end

Closures

Closures can arise from the mixed use of lexically scoped local variables, and higher order functions. Any function that makes use of non-local variables effectively keeps those variable references alive within it. An example explains this better:

function make_counter()
  local count = 0
  return function()
    count = count + 1
    print(count)
  end
end

-- call to make_counter() returns a function;
-- and 'captures' the local count as an 'upvalue' specific to it
local c1 = make_counter()
c1()  -- prints: 1
c1()  -- prints: 2
c1()  -- prints: 3

-- another call to make_counter() creates a new function,
-- with a new count upvalue
local c2 = make_counter()
c2()  -- prints: 1
c2()  -- prints: 2

-- the two function's upvalues are independent of each other:
c1()  -- prints: 4

This technique can be incredibly powerful. An object constructor and its private data can be entirely ecapsulated through the use of upvalues, for example.

Coroutines

Coroutines are a form of collaborative multi-tasking. You can think of them as functions that can be paused in mid execution, to be resumed at that position at a later time.

The C programmer can think of them as similar to threads, however they are explicitly paused and resumed from within a script (rather than by the operating system), and do not make use of CPU multithreading capabilities.

A coroutine is created from an existing function using coroutine.create(), and is resumed using coroutine.resume(). It can pause itself with coroutine.yield(). In addition, values can be passed back and forth via the arguments to coroutine.resume() and coroutine.yield().

local resume, yield = coroutine.resume, coroutine.yield

-- this function will be used to create a coroutine:

local function loop()
  print("hello!")
  local x = 0
  while true do
    -- pause function here:
    yield(x)
    -- continues here:
    x = x + 1
    print(x)
  end
end

-- create the coroutine:
local c = coroutine.create(loop)

-- the first resume runs from the start of the loop() function to the first yield():
coroutine.resume(c) -- prints: hello!

-- each subsequent resume runs from the last paused yield() to the next yield():
coroutine.resume(c) -- prints: 1
coroutine.resume(c) -- prints: 2

In LuaAV, coroutines are extended for accurate temporal scheduling, using the gowait and now functions.

Advanced Topics

Metatables

Lua does not provide a class-based object-oriented system by default; instead it provides the meta-mechanisms with which many different kinds of object-oriented programming styles can be implemented.

There are several special events that can apply to objects (usually tables and userdata); the default behavior for these events can be overridden by means of a metatable. A metatable is just an ordinary table with some reserved key names bound to functions (metamethods) to specify this variant behavior. Any table or userdata can have its metatable set; some objects may share a metatable.

For example, the __add metamethod defines what happens when two objects are added to each other:

-- a metatable for pairs
local pair_meta = {}

-- a metamethod function for how to add two pairs together:
pair_meta.__add = function(a, b)
local p = {
  a[1]+b[1],
  a[2]+b[2],
}
-- result is also a pair:
setmetatable(p, pair_meta)
  return p
end

-- a constructor for pairs:
function make_pair(x, y)
  local p = { x, y }
  -- tell p to look in pair_meta for how to handle metamethod events:
  setmetatable(p, pair_meta)
  return p
end

-- create two pairs:
local p1 = make_pair(2, 3)
local p2 = make_pair(4, 5)

-- add them (creates a new pair):
local p3 = p1 + p2
print(p3[1], p3[2]) -- prints: 6 8

Arithmetic operator metamethods also exist for __mul, __sub, __div, __mod, __pow, __unm (unary negation).

The __index metamethod is important: if a key cannot be found in a given table, it will try again in whichever object the __index field points to; or call the function if __index points to a function. This is the principal way that inheritence (of both class data and methods) is supported:

local animal = {}

function animal:isalive() print("yes!") end

local dog = {}
function dog:talk() print("bark!") end

-- create metatable for dog, that refers to animal for unknown keys:
local dog_meta = { __index = animal }

-- apply metatable to dog:
setmetatable(dog, dog_meta)

-- test it:
dog:talk()  -- prints: bark!
dog:isalive() -- prints: yes!

animal:talk() -- error!

A corresponding __newindex metamethod exists to handle assignments of new keys to an object.

Other metamethods include __tostring to convert an object to a string (in the print() and tostring() functions), __eq, __lt and __le for logical comparisons, __concat for the .. operator, __len for the # operator, and __call for the () operator.

By combining all of these metamethods, and smart use metatables, various forms of class based inheritance can be designed. Several examples can be found here.

Userdata and the C API

Userdata are objects that encapsulate arbitrary C/C++ data within a Lua interface. Many Lua modules extend the capabilities of Lua by binding external libraries, including the creation of new types as userdata. For example, the built-in module io includes means to create, and modify files on the system, which are represented as userdata.

There are two kinds of userdata: lightuserdata are simply raw pointers, and there is nothing that can be done with them (they have no methods, and are immutable), except for passing them into other C functions. They are rarely used. Full userdata on the other hand behave more like tables, with possible metatables, and local environment data; they are also subject to garbage collection and have a special __gc metamethod for it.

Binding C functions and objects to Lua is done via the C API only, and cannot be done from within Lua itself. It is a complex subject and beyond the scope of this tutorial!

This entry was posted in Tutorials. Bookmark the permalink.

2 Responses to Lua Tutorial

  1. Pingback: harvey

  2. Pingback: Anonymous

Leave a Reply