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. Lua does not contain explicit support for
inheritance, but allows it to be implemented 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 techniques from
functional programming and full
lexical scoping allows fine-grained
information hiding to enforce the
principle of least privilege. In general, Lua strives to provide simple, flexible
meta-features that can be extended as needed, rather than supply a feature-set specific to one programming paradigm. As a result, the base language is
light; the full reference
interpreter is only about 247
kB compiled print("Hello, World!") print "Hello, World!" The declaration of a variable, without a value. local variable The declaration of a variable with a value of 1000 (one thousand) local students = 1000 A
comment in Lua starts with a double-hyphen and runs to the end of the line, similar to
Ada,
Eiffel,
Haskell,
SQL and
VHDL. Multi-line strings and comments are marked with double square brackets. -- Single line comment --
Multi-line comment -- The
factorial function is implemented in this example: function factorial(n) local x = 1 for i = 2, n do x = x * i end return x end
Control flow Lua has one type of
conditional test:
if then end with optional else and elseif then execution control constructs. The generic if then end statement requires all three keywords: if condition then --statement body end An example of an if statement if x ~= 10 then print(x) end The else keyword may be added with an accompanying statement block to control execution when the if condition evaluates to false: if condition then --statement body else --statement body end An example of an if else statement if x == 10 then print(10) else print(x) end Execution may also be controlled according to multiple conditions using the elseif then keywords: if condition then --statement body elseif condition then --statement body else -- optional --optional default statement body end An example of an if elseif else statement if x == y then print("x = y") elseif x == z then print("x = z") else -- optional print("x does not equal any other variable") end Lua has four types of conditional loops: the
while loop, the repeat loop (similar to a
do while loop), the numeric
for loop and the generic for loop. --condition = true while condition do --statements end repeat --statements until condition for i = first, last, delta do --delta may be negative, allowing the for loop to count down or up --statements --example: print(i) end This generic for loop would iterate over the table _G using the standard iterator function pairs, until it returns nil: for key, value in pairs(_G) do print(key, value) end Loops can also be
nested (put inside of another loop). local grid = { { 11, 12, 13 }, { 21, 22, 23 }, { 31, 32, 33 } } for y, row in pairs(grid) do for x, value in pairs(row) do print(x, y, value) end end
Functions Lua's treatment of functions as
first-class values is shown in the following example, where the print function's behavior is modified: do local oldprint = print -- Store current print function as oldprint function print(s) --
Redefine print function. The usual print function can still be used through oldprint. The new one has only one argument. oldprint(s == "foo" and "bar" or s) end end 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 the current scope and whose lifetime would be shorter than that of this anonymous function, Lua creates a closure. return x + y end end fourplus = addto(4) print(fourplus(3)) -- Prints 7 --This can also be achieved by calling the function in the following way: print(addto(4)(3)) --
This is because we are calling the returned function from 'addto(4)' with the argument '3' directly. This also helps to reduce data cost and up performance if being called iteratively. A new closure for the variable x is created every time addto is called, so that each new 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 Tables are the most important data structures (and, by design, the only built-in
composite data type) in Lua and are the foundation of all user-created types. They are associative arrays with addition of automatic numeric key and special syntax. A table is a set of key and data pairs, where the data is referenced by key; in other words, it is a
hashed heterogeneous associative array. Tables are created using the {} constructor syntax. a_table = {} -- Creates a new, empty table Tables are always passed by reference (see
Call by sharing). A key (index) can be any value except nil and
NaN, including functions. 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. A table is often used as
structure (or
record) by using
strings as keys. Because such use is very common, Lua features a special syntax for accessing such fields. point = { x = 10, y = 20 } -- Create new table print(point["x"]) -- Prints 10 print(point.x) -- Has exactly the same meaning as line above. The easier-to-read dot notation is just syntactic sugar. 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} -- return {["x"] = x, ["y"] = y} end Point.set_x = function(point, x) point.x = x -- point["x"] = x; end Tables are automatically assigned a numerical key, enabling them to be used as an
array data type. The first automatic index is 1 rather than 0 as it is for many other programming languages (though an explicit index of 0 is allowed). A numeric key 1 is distinct from a string key "1". 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). ExampleTable = { {1, 2, 3, 4}, {5, 6, 7, 8} } print(ExampleTable[1][3]) -- Prints "3" print(ExampleTable[2][4]) -- Prints "8" A table can be an array of objects. function Point(x, y) -- "Point" object constructor return { x = x, y = y } -- Creates and returns a new object (table) end array = { Point(10, 20), Point(30, 40), Point(50, 60) } -- Creates array of points -- array = { { x = 10, y = 20 }, { x = 30, y = 40 }, { x = 50, y = 60 } }; print(array[2].y) -- Prints 40 Using a hash map to emulate an array is normally slower than using an actual array; however, Lua tables are optimized for use as arrays to help avoid this issue.
Metatables Extensible semantics is a key feature of Lua, and the metatable allows powerful customization of tables. The following example demonstrates an "infinite" table. For any n, fibs[n] will give the n-th
Fibonacci number using
dynamic programming and
memoization. fibs = { 1, 1 } -- Initial values for fibs[1] and fibs[2]. setmetatable(fibs, { __index = function(values, n) --
__index is a function predefined by Lua, it is called if key "n" does not exist. values[n] = values[n - 1] + values[n - 2] -- Calculate and memoize fibs[n]. return values[n] end })
Object-oriented programming Although Lua does not have a built-in concept of
classes,
object-oriented programming can be emulated using functions and tables. An object is formed by putting methods and fields in a table.
Inheritance (both single and multiple) can be implemented with
metatables, delegating nonexistent methods and fields to a parent object. There is no such concept as "class" with these techniques; rather,
prototypes are used, similar to
Self or
JavaScript. New objects are created either with a
factory method (that constructs new objects from scratch) or by cloning an existing object. Creating a basic
vector object: local Vector = {} local VectorMeta = { __index = Vector} function Vector.new(x, y, z) -- The constructor return setmetatable({x = x, y = y, z = z}, VectorMeta) end function Vector.magnitude(self) -- Another method return math.sqrt(self.x^2 + self.y^2 + self.z^2) end local vec = Vector.new(0, 1, 0) -- Create a vector print(vec.magnitude(vec)) -- Call a method (output: 1) print(vec.x) -- Access a member variable (output: 0) Here, tells Lua to look for an element in the table if it is not present in the table. , which is equivalent to , first looks in the table for the element. The table does not have a element, but its metatable delegates to the table for the element when it's not found in the table. Lua provides some
syntactic sugar to facilitate object orientation. To declare
member functions inside a prototype table, one can use , which is equivalent to . Calling class methods also makes use of the colon: is equivalent to . That in mind, here is a corresponding class with syntactic sugar: local Vector = {} Vector.__index = Vector function Vector:new(x, y, z) -- The constructor -- Since the function definition uses a colon, -- its first argument is "self" which refers -- to "Vector" return setmetatable({x = x, y = y, z = z}, self) end function Vector:magnitude() -- Another method -- Reference the implicit object using self return math.sqrt(self.x^2 + self.y^2 + self.z^2) end local vec = Vector:new(0, 1, 0) -- Create a vector print(vec:magnitude()) -- Call a method (output: 1) print(vec.x) -- Access a member variable (output: 0)
Inheritance It is possible to use metatables to mimic the behavior of class inheritance in Lua. In this example, we allow vectors to have their values multiplied by a constant in a derived class. local Vector = {} Vector.__index = Vector function Vector:new(x, y, z) -- The constructor -- Here, self refers to whatever class's "new" -- method we call. In a derived class, self will -- be the derived class; in the Vector class, self -- will be Vector return setmetatable({x = x, y = y, z = z}, self) end function Vector:magnitude() -- Another method -- Reference the implicit object using self return math.sqrt(self.x^2 + self.y^2 + self.z^2) end -- Example of pseudo class inheritance local VectorMult = {} VectorMult.__index = VectorMult setmetatable(VectorMult, Vector) -- Make VectorMult a child of Vector function VectorMult:multiply(value) self.x = self.x * value self.y = self.y * value self.z = self.z * value return self end local vec = VectorMult:new(0, 1, 0) -- Create a vector print(vec:magnitude()) -- Call a method (output: 1) print(vec.y) -- Access a member variable (output: 1) vec:multiply(2) -- Multiply all components of vector by 2 print(vec.y) -- Access member again (output: 2) It is also possible to implement
multiple inheritance; can either be a function or a table.
Operator overloading can also be done; Lua metatables can have elements such as , and so on. == Implementation ==