Lua

Topics related to Lua:

Getting started with Lua

Lua logo

Lua is minimalistic, lightweight and embeddable scripting language. It's being designed, implemented, and maintained by a team at PUC-Rio, the Pontifical Catholic University of Rio de Janeiro in Brazil. The mailing list is open to get involved.

Common use-cases for Lua includes scripting video games, extending applications with plugins and configs, wrapping some high-level business logic or just embedding into devices like TVs, cars, etc.

For high performance tasks there is independent implementation using just-in-time-compiler available called LuaJIT.

Introduction to Lua C API

Lua as well provides a proper C API to it's Virtual Machine. In contrary to VM itself, C API interface is stack based. So, most of the functions intended to be used with data is either adding some stuff on-top of virtual stack, or removing from it. Also, all the API calls must be used carefully within stack and it's limitations.

In general, anything available on Lua language can be done using it's C API. Also, there is some addition functionality like direct access to internal registry, change behavior of standard memory allocator or garbage collector.

You can compile provided Lua C API examples by executing following on Your terminal:

$ gcc -Wall ./example.c -llua -ldl -lm

Tables

Tables are the only built-in data structure available in Lua. This is either elegant simplicity or confusing, depending on how you look at it.

A Lua table is a collection of key-value pairs where the keys are unique and neither the key nor the value is nil. As such, a Lua table can resemble a dictionary, hashmap or associative array from other languages. Many structural patterns can be built with tables: stacks, queues, sets, lists, graphs, etc. Finally, tables can be used to build classes in Lua and to create a module system.

Lua does not enforce any particular rules on how tables are used. The items contained in a table can be a mixture of Lua types. So, for example, one table could contain strings, functions, booleans, numbers, and even other tables as values or keys.

A Lua table with consecutive positive integer keys beginning with 1 is said to have a sequence. The key-value pairs with positive integer keys are the elements of the sequence. Other languages call this a 1-based array. Certain standard operations and functions only work on the sequence of a table and some have non-deterministic behavior when applied to a table without a sequence.

Setting a value in a table to nil removes it from the table. Iterators would no longer see the related key. When coding for a table with a sequence, it is important to avoid breaking the sequence; Only remove the last element or use a function, like the standard table.remove, that shifts elements down to close the gap.

Writing and using modules

The basic pattern for writing a module is to fill a table with keys that are function names and values that are the functions themselves. The module then returns this function for calling code to require and use. (Functions are first-class values in Lua, so storing a function in a table is easy and common.) The table can also contain any important constants in the form of, say, strings or numbers.

Functions

Functions are usually set with function a(b,c) ... end and rarely with setting a variable to an anonymous function (a = function(a,b) ... end). The opposite is true when passing functions as parameters, anonymous functions are mostly used, and normal functions aren't used as often.

Metatables

Booleans in Lua

Booleans, truth, and falsity are straightforward in Lua. To review:

  1. There is a boolean type with exactly two values: true and false.
  2. In a conditional context (if, elseif, while, until), a boolean is not required. Any expression can be used.
  3. In a conditional context, false and nil count as false, and everything else counts as true.
  4. Although 3 already implies this: if you're coming from other languages, remember that 0 and the empty string count as true in conditional contexts in Lua.

Coroutines

The coroutine system has been implemented in lua to emulate multithreading existing in other languages. It works by switching at extremely high speed between different functions so that the human user think they are executed at the same time.

Sets

Iterators

Variadic Arguments

Efficiency

The vararg list is implemented as a linked list in the PUC-Rio implementation of the language, this means that indexes are O(n). That means that iterating over the elements in a vararg using select(), like the example below, is an O(n^2) operation.

for i = 1, select('#', ...) do
    print(select(i, ...))
end

If you plan on iterating over the elements in a vararg list, first pack the list into a table. Table accesses are O(1), so iterating is O(n) in total. Or, if you are so inclined, see the foldr() example from the advanced usage section; it uses recursion to iterate over a vararg list in O(n).

Sequence Length Definition

The vararg is useful in that the length of the vararg respects any explicitly passed (or computed) nils. For example.

function test(...)
    return select('#', ...)
end

test()             --> 0
test(nil, 1, nil)  --> 3

This behavior conflicts with the behavior of tables however, where the length operator # does not work with 'holes' (embedded nils) in sequences. Computing the length of a table with holes is undefined and cannot be relied on. So, depending upon the values in ..., taking the length of {...} may not result in the 'correct' answer. In Lua 5.2+ table.pack() was introduced to handle this deficiency (there is a function in the example that implements this function in pure Lua).

Idiomatic Use

Because varargs carry around their length people use them as sequences to avoid the issue with holes in tables. This was not their intended usage and one the reference implementation of Lua does not optimize for. Although such usage is explored in the examples, it is generally frowned upon.

Error Handling

Garbage collector and weak tables

Pattern matching

Throughout some examples, the notation (<string literal>):function <string literal> is used, which is equivalent to string.function(<string literal>, <string literal>) because all strings have a metatable with the __index field set to the string table.

PICO-8

Object-Orientation