Saltar a contenido

Notes on Lua 5.1

Chunks and variables

Each piece of code that Lua executes, such as a file or a single line in interactive mode, is a chunk. A chunk may be a single statement or a mix of statements and function definitions. Actually function definitions are just assignments. So a chunk is always composed of statements.

Statements are what you would guess. They might be followed by a semicolon. The following chunks are all valid and equivalent:

a = 1
b = a*2
a = 1;
b = a*2;
a = 1 ; b = a*2
a = 1   b = a*2 -- ugly, but valid

Global variables do not need declarations. You simply assign a value to a global variable to create it.

1
2
3
print(b)  --> nil
b = 10
print(b)  --> 10

Assigning nil deletes a global variable. You should use a local variable when possible.

local a = "20"

Types

Lua is a dynamically typed language. There are no type definitions in the language.

There are eight basic types in Lua: nil, boolean, number, string, userdata, function, thread, and table.

The type function gives the type name of a given value.

1
2
3
4
5
6
7
print(type("Hello world"))  --> string
print(type(10.4*3))         --> number
print(type(print))          --> function
print(type(type))           --> function
print(type(true))           --> boolean
print(type(nil))            --> nil
print(type(type(X)))        --> string 
The last example will result in "string" no matter the value of X, because the result of type is always a string.

Functions are first-class values in Lua; so, we can manipulate them like any other value.

1
2
3
4
a = "some string"
print(type(a))   --> will output 'string'
a = print
a(type(a))       --> will output 'function'

nil is the absence of value.

Conditionals (such as the ones in control structures) consider false and nil as false and anything else as true. Beware that, unlike some other scripting languages, Lua considers both zero and the empty string as true in conditional tests.

The number type represents real (double-precision floating-point) numbers. Lua has no integer type.

Strings may contain characters with any numeric value, including embedded zeros. That means that you can store any binary data into a string. Strings in Lua are immutable values. To mutate you create a new string with the desired modifications, as in the next example:

1
2
3
4
    a = "one string"
    b = string.gsub(a, "one", "another")  -- change string parts
    print(a)       --> one string
    print(b)       --> another string

We can delimit literal strings by matching single or double quotes.

Strings in Lua can contain the following C-like escape sequences:

\a  bell
\b  back space
\f  form feed
\n  newline
\r  carriage return
\t  horizontal tab
\v  vertical tab
\\  backslash
\"  double quote
\'  single quote
\[  left square bracket
\]  right square bracket
We can specify a character in a string also by its numeric value through the escape sequence \ddd, where ddd is a sequence of up to three decimal digits

We can delimit literal strings also by matching double square brackets [[...]]. Literals in this bracketed form may run for several lines, may nest, and do not interpret escape sequences.

Lua provides automatic conversions between numbers and strings at run time. Lua applies such coercions not only in arithmetic operators, but also in other places that expect a number.

1
2
3
    print("10" + 1)           --> 11
    print("10 + 1")           --> 10 + 1
    print("hello" + 1)        -- ERROR (cannot convert "hello")

Conversely, whenever it finds a number where it expects a string, Lua converts the number to a string. .. is the string concatenation operator. When you write it right after a numeral, you must separate them with a space; otherwise, Lua thinks that the first dot is a decimal point.

    print(10 .. 20)        --> 1020

A comparison like 10 == "10" is always false. If you need to convert a string to a number explicitly, you can use the function tonumber, which returns nil if the string does not denote a proper number.

To convert a number to a string, you can call the function tostring or concatenate the number with the empty string:

    print(tostring(10) == "10")   --> true
    print(10 .. "" == "10")       --> true

Tables are the main (in fact, the only) data structuring mechanism in Lua. You can add as many elements as you want to a table dynamically. The table type implements associative arrays. An associative array is an array that can be indexed not only with numbers, but also with strings or any other value of the language, except nil.

All structures that other languages offer---arrays, records, lists, queues, sets---are represented with tables in Lua.

Lua uses tables to represent packages as well. When we write io.read, we mean "the read entry from the io package". For Lua, that means "index the table io using the string "read" as the key".

The table type implements associative arrays. An associative array is an array that can be indexed not only with numbers, but also with strings or any other value of the language, except nil.

Tables in Lua are neither values nor variables; they are objects.

You may think of a table as a dynamically allocated object; your program only manipulates references (or pointers) to them.

There are no hidden copies or creation of new tables behind the scenes. Moreover, you do not have to declare a table in Lua; in fact, there is no way to declare one.

You create tables by means of a constructor expression, which in its simplest form is written as {}:

1
2
3
4
5
6
7
8
9
    a = {}     -- create a table and store its reference in `a'
    k = "x"
    a[k] = 10        -- new entry, with key="x" and value=10
    a[20] = "great"  -- new entry, with key=20 and value="great"
    print(a["x"])    --> 10
    k = 20
    print(a[k])      --> "great"
    a["x"] = a["x"] + 1     -- increments entry "x"
    print(a["x"])    --> 11

A table is always anonymous. There is no fixed relationship between a variable that holds a table and the table itself:

1
2
3
4
5
6
7
8
    a = {}
    a["x"] = 10
    b = a      -- `b' refers to the same table as `a'
    print(b["x"])  --> 10
    b["x"] = 20
    print(a["x"])  --> 20
    a = nil    -- now only `b' still refers to the table
    b = nil    -- now there are no references left to the table

When a program has no references to a table left, Lua memory management will eventually delete the table and reuse its memory.

Each table may store values with different types of indices and it grows as it needs to accommodate new entries.

Lua stores global variables in ordinary tables, so just like global variables, table fields evaluate to nil if they are not initialized and assigning nil to a table field deletes it.

To represent records, you use the field name as an index. Lua supports this representation by providing a.name as syntactic sugar for a["name"].

1
2
3
    a.x = 10                    -- same as a["x"] = 10
    print(a.x)                  -- same as print(a["x"])
    print(a.y)                  -- same as print(a["y"])

Do not confuse a.x with a[x]. The first form represents a["x"], that is, a table indexed by the string "x". The second form is a table indexed by the value of the variable x.

1
2
3
4
5
6
    a = {}
    x = "y"
    a[x] = 10                 -- put 10 in field "y"
    print(a[x])   --> 10      -- value of field "y"
    print(a.x)    --> nil     -- value of field "x" (undefined)
    print(a.y)    --> 10      -- value of field "y"

Data structures

To represent an array use a table with integer keys. There is no way to declare its size, just initialize the elements needed:

For example we could take 10 user inputs and store them in a table with an integer index as the key.

1
2
3
4
    a = {}
    for i=1,10 do
      a[i] = io.read()
    end

When iterating over the elements of the array, the first non-initialized index will result in nil. We can set a convention to interpret this first nil value as the end of the array. The Lua standard library provides ipairs, a function that iterates over the elements of an array following the convention that the array ends at its first nil element.

1
2
3
    for i,line in ipairs(a) do
      print(line)
    end

Since you can index a table with any value, you can start the indices of an array with any number that pleases you. However, it is customary in Lua to start arrays with one (and not with zero, as in C) and the standard libraries stick to this convention.

Because we can index a table with any type, when indexing a table we have the same subtleties that arise in equality. Although we can index a table both with the number 0 and with the string "0", these two values are different (according to equality) and therefore denote different positions in a table. By the same token, the strings "+1", "01", and "1" all denote different positions. When in doubt about the actual types of your indices, use an explicit conversion to be sure:

1
2
3
4
5
6
7
8
9
    i = 10; j = "10"; k = "+10"
    a = {}
    a[i] = "one value"
    a[j] = "another value"
    a[k] = "yet another value"
    print(a[j])            --> another value
    print(a[k])            --> yet another value
    print(a[tonumber(j)])  --> one value
    print(a[tonumber(k)])  --> one value

You can introduce subtle bugs in your program if you do not pay attention to this point.

Functions

Functions are first-class values in Lua. That means that functions can be stored in variables, passed as arguments to other functions, and returned as results. Such facilities give great flexibility to the language: A program may redefine a function to add new functionality, or simply erase a function to create a secure environment when running a piece of untrusted code (such as code received through a network). Moreover, Lua offers good support for functional programming, including nested functions with proper lexical scoping; just wait. Finally, first-class functions play a key role in Lua's object-oriented facilities, as we will see in Chapter 16. Lua can call functions written in Lua and functions written in C. All the standard library in Lua is written in C. It comprises functions for string manipulation, table manipulation, I/O, access to basic operating system facilities, mathematical functions, and debugging. Application programs may define other functions in C.

Userdata and Threads

The userdata type allows arbitrary C data to be stored in Lua variables. It has no predefined operations in Lua, except assignment and equality test. Userdata are used to represent new types created by an application program or a library written in C; for instance, the standard I/O library uses them to represent files. We will discuss more about userdata later, when we get to the C API.

Expressions

Expressions denote values. Expressions in Lua include the numeric constants and string literals, variables, unary and binary operations, and function calls. Expressions can be also the unconventional function definitions and table constructors.

Examples

  • example a
  • example b

Applications in the wild

Sources