Jump to content

  • Log in with Facebook Log in with Twitter Log In with Steam Log In with Google Sign In
  • Create Account

Tutorial info Visit support topic

  • Added on: Feb 27 2013 02:42 PM
  • Views: 1409

Lua (programming language)

Lua is commonly described as a “multi-paradigm” language, providing a small set of general features that can be extended to fit different problem types, rather than providing a more complex and rigid specification to match a single paradigm. Lua, for instance, does not contain explicit support for inheritance, but allows it to be implemented relatively easily with metatables. Similarly, Lua allows programmers to implement namespaces, classes, and other related features using its single table implementation; first-class functions allow the employment of many powerful techniques from functional programming; and full lexical scoping allows fine-grained information hiding to enforce the principle of least privilege.

Posted by Jopa on Feb 27 2013 02:42 PM
Example code

The classic  hello world program can be written as follows:



print("Hello World!")

Comments use the following syntax, similar to that of Ada, Eiffel, SOL and VHDL:



-- A comment in Lua starts with a double-hyphen and runs to the end of the line.
--[[ Multi-line strings & comments
are adorned with double square brackets. ]]
--[=[ Comments like this can have other --[[comments]] nested. ]=]

The factorial function is implemented as a recursive function in this example:



function factorial(n)
if n == 0 then
    return 1
    return n * factorial(n - 1)

Lua has four types of loops: the while loop, the repeat loop, the for loop, and the generic for loop. (The local variables defined are to simply make the program complete. User variables are expected to be the normal input parameters for these functions.)

The while loop has the syntax:



while condition do

The repeat loop:


local cond = false
until cond

executes the loop body at least once, and would keep looping until cond becomes true.


The for loop:


for index = 1,5 do

would repeat the loop body 5 times, outputting the numbers 1 through 5 inclusive.


Another form of the for loop is:


local start,finish,delta = 10,1,-1 --delta may be negative, allowing the for loop to count down or up.
for index = start,finish,delta do

The generic for loop:


for key,value in pairs(_G) do

would iterate over the table _G using the standard iterator function pairs, until it returns nil.




Lua’s treatment of functions as first-class values is shown in the following example, where the print function’s behavior is modified:


local oldprint = print -- Store current print function as oldprint
function print(s) -- Redefine print function, the usual print function can still be used
  if s == "foo" then

Any future calls to print will now be routed through the new function, and because of Lua’s lexical scoping, the old print function will only be accessible by the new, modified print.


Lua also supports closures, as demonstrated below:


function addto(x)
-- Return a new function that adds x to the argument
return function(y)
  --[[ When we refer to the variable x, which is outside of the current
     scope and whose lifetime is longer than that of this anonymous
     function, Lua creates a closure.]]
  return x + y
fourplus = addto(4)
print(fourplus(3)) -- Prints 7

A new closure for the variable x is created every time addto is called, so that the anonymous function returned will always access its own x parameter. The closure is managed by Lua’s garbage collector, just like any other object.


Tables are created using the {} constructor syntax:


a_table = {} -- Creates a new, empty table

Tables are always passed by reference:


a_table = {x = 10} -- Creates a new table, with one entry mapping "x" to the number 10.
print(a_table["x"]) -- Prints the value associated with the string key, in this case 10.
b_table = a_table
b_table["x"] = 20 -- The value in the table has been changed to 20.
print(b_table["x"]) -- Prints 20.
print(a_table["x"]) -- Also prints 20, because a_table and b_table both refer to the same table.

We can insert/remove values/indexes from tables, as well.


local myTable={"a","b"}
table.insert(myTable,"c") --print(unpack(myTable)) --> a b c
table.remove(myTable,2) --print(unpack(myTable)) --> a c
As record

A table is often used as sructure (or record) by using strings as keys. Because such use is very common, Lua features a special syntax for accessing such fields. Example:


point = { x = 10, y = 20 } -- Create new table
print(point["x"]) -- Prints 10
print(point.x) -- Has exactly the same meaning as line above
As namespace

By using a table to store related functions, it can act as a namespace.


Point = {}

Point.new = function(x, y)
  return {x = x, y = y}

Point.set_x = function(point, x)
  point.x = x
As array

By using a numerical key, the table resembles an arraydata tipe. Lua arrays are 1-based: the first index is 1 rather than 0 as it is for many other programming languages (though an explicit index of 0 is allowed).

A simple array of strings:


array = { "a", "b", "c", "d" }             -- Indices are assigned automatically.
print(array[2])                            -- Prints "b". Automatic indexing in Lua starts at 1.
print(#array)                              -- Prints 4. # is the length operator for tables and strings.
array[0] = "z"                             -- Zero is a legal index.
print(#array)                              -- Still prints 4, as Lua arrays are 1-based.

The length of a table t is defined to be any integer index n such that t[n] is not nil and t[n+1] is nil; moreover, if t[1] is nil, n can be zero. For a regular array, with non-nil values from 1 to a given n, its length is exactly that n, the index of its last value. If the array has "holes" (that is, nil values between other non-nil values), then #t can be any of the indices that directly precedes a nil value (that is, it may consider any such nil value as the end of the array).


An array of objects:


function Point(x, y)                            -- "Point" object constructor
return { x = x, y = y }                         -- Creates and returns a new object (table)
array = { Point(10, 20), Point(30, 40), Point(50, 60) }         -- Creates array of points
print(array[2].y)                                               -- Prints 40

Using a hash map to emulate an array normally is slower than using an actual array; however, Lua tables are optimized for use as arrays to help avoid this issue.



Extensible semantics is a key feature of Lua, and the metatable concept allows Lua’s tables to be customized in powerful ways.



fibs = { 1, 1 }                                  -- Initial values for fibs[1] and fibs[2].
setmetatable(fibs, {
__index = function(name, n)                      -- Call this function if fibs[n] does not exist.
name[n] = name[n - 1] + name[n - 2]              -- Calculate and memoize fibs[n].
return name[n]

Another example, with the __call metamethod to create an Object Oriented Programming feel:


newPerson = {} -- Creates a new table called 'newPerson'.

setmetatable(newPerson, {
__call = function(table,name,age)           -- Turns the newPerson table into a functable.
local person = {Name = name, Age = age}     -- Creates a local variable which has all the properties of the person you create later on.  
return person -- Returns the table person so when you create it, it will set the variables in the table person.

Bill = newPerson("Bill Raizer", 21)         -- Creates a new person.
print(Bill.Name, Bill.Age)                  -- Prints the name and age.

Creating a basic vector object:


Vector = {}                                -- Create a table to hold the class methods
function Vector:new(x, y, z)               -- The constructor
local object = { x = x, y = y, z = z }
setmetatable(object, { __index = Vector }) -- Inheritance
return object
function Vector:magnitude()               -- Another member function
   -- Reference the implicit object using self
return math.sqrt(self.x^2 + self.y^2 + self.z^2)

vec = Vector:new(0, 1, 0)                 -- Create a vector
print(vec:magnitude())                    -- Call a member function using ":" (output: 1)
print(vec.x)                              -- Access a member variable using "." (output: 0)

This example is the bytecode listing of the factorial function defined above (as shown by the luac 5.1 compiler):




function <factorial.lua:1,6> (10 instructions, 40 bytes at 003D5818)
1 param, 3 slots, 0 upvalues, 1 local, 3 constants, 0 functions
        1       [2]     EQ              0 0 -1  ; - 0
        2       [2]     JMP             2       ; to 5
        3       [3]     LOADK           1 -2    ; 1
        4       [3]     RETURN          1 2
        5       [5]     GETGLOBAL       1 -3    ; factorial
        6       [5]     SUB             2 0 -2  ; - 1
        7       [5]     CALL            1 2 2
        8       [5]     MUL             1 0 1
        9       [5]     RETURN          1 2
        10      [6]     RETURN          0 1

Here is an example of calling a Lua function from C:


#include <stdio.h>
#include <stdlib.h>
#include <lua.h>
#include <lauxlib.h>

int main()
   lua_State *L = luaL_newstate();
   if (luaL_dostring(L, "function foo (x,y) return x+y end")) exit(1);
   lua_getglobal(L, "foo");
   lua_pushinteger(L, 5);
   lua_pushinteger(L, 3);
   lua_call(L, 2, 1);
   printf("Result: %d\n", lua_tointeger(L, -1));
   return 0;


Running this example gives:



$ gcc -o example -llua example.c
$ ./example
Result: 8