Topic 00-intro.md

An Introduction to Lua

This introduction assumes that you have some familiarity with basic programming.

We recommend that you get a good programmer’s editor which understands Lua syntax and can highlight it appropriately. This is not just because it’s more attractive, but such an editor can immediately show you common mistakes like forgetting the closing quote on a string. Such editors can also match up parentheses and braces. They will often automatically indent code for you, which is important for readability. Lua support is common these days; SciTE is a good example of a straightforward yet powerful editor, and ZeroBrane Studio is a full IDE providing debugger support. See the Lua wiki for more options.

It is better to lay out code like this:

 for i = 1,10 do
     if i < 5 then
         print("lower",i)
     else
         print("upper",i)
     end
 end

Than this:

 for i = 1,10 do
 if i < 5 then
 print("lower",i) else
 print("upper",i)
 end
 end

The logical structure of the code is now harder to see. By making indenting a habit, you will write code that will be more readable to another person. (After several months, you will be that other person.)

Expressions

It is traditional to start with “Hello, world”. Like all scripting languages, this is straightforward:

 print("Hello world")

An important point is that print is a function which takes a number of values and prints out these values to standard output. It is not a statement, as in Python 2.X or Basic.

To run this example, save this line as ‘hello.lua’ and run from the command line:

 $> lua hello.lua
 Hello world!

(Or, use an editor that knows how to run Lua, like SciTE in Lua for Windows. The F5 key will run the current program; it is F6 in ZBStudio)

Arithmetic expressions use standard programming notation:

 print("result",2 + 3 * 4 ^ 2)

There is an exponentiation (‘power of’) operator ^, unlike in C or Java.

The order of evaluation follows the usual rules, and you can use parentheses to group expressions – for example, (1 + 2)*(3 + 4). The original expression could be written like:

 (2 + (3 * (4 ^ 2))

which makes the order obvious. When in doubt, use parentheses, but knowing when you have to use them is an important part of learning a programming language.

Operations like + and * are called operators, and the values they operate on are called arguments.

There is a remainder operator, % which gives the integer remainder from a division:

 print(1 % 2) --> 1
 print(2 % 2)  --> 0
 print(3 % 2) --> 1

There are the usual standard mathematical functions available in the math namespace (or table) like math.sin , math.sqrt ,etc. The useful constant math.pi is also available.

 print('sin', math.sin(0.5*math.pi), 'cos', math.cos(0.5*math.pi))

This is more readable when spread over two lines using a variable x:

 x = 0.5*math.pi
 print('sin',math.sin(x),'cos',math.sin(x))

(Of course, x is not a variable in this case, but Lua does not make any distinction between variables and named constants.)

Even if the command-line is not your strong point, I recommend learning Lua interactively. !5.1.5!

 $> lua
 Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
 > print(10 + 20)
 30
 > = 10 + 20
 30
 > = math.sin(2.3)
 0.74570521217672
 > p = math.pi
 > = math.cos(p)
 -1

Starting a line with = is a shortcut for return .... Interactive Lua is a very useful scientific calculator !

!LfW! With Lua for Windows, it is not even necessary to open a command prompt. On the SciTE toolbar, there is a prompt icon with the tooltip ‘Launch Interactive Lua’. It will open an interactive session in the output pane, and you can evaluate Lua statements. As with a console prompt, the up and down arrows can be used to select and re-evaluate previous statements.

Variables and Assignment

Lua variables may have letters, digits and underscores (‘_’), but they cannot start with a digit. So check_number, checkNumber, and catch21 are fine, but 21catch is not. There is no limit to the length of variable names, except the patience of you and your readers.

Variables are case-sensitive. ERROR,Error and error are all different variables.

They may contain any Lua type:

 x = "hello"
 x = 1
 x = x + 1

Here, the value of x becomes “hello”, and then it becomes 1, and finally 2 (which is the value of x + 1). This process is commonly called assignment.

Variables have no fixed type, but always contain a definite type of value, even if it is just nil.

Assigning multiple variables works like this:

 x, y = 1, 2

This sets x to 1 and y to 2. This is different from the usual x=1, y=2 style in other languages. It is possible to swap the values of two variables in one line:

 x, y = y, x

The assignment statement x = 1 is not an expression – it does not return a value as in C or Java.

Numeric for loops

Programming is more than calculation. The simplest way to do something a number of times is the numeric for statement:

 for i = 1, 5 do
     print("hello",i)
 end
 -->
 hello   1
 hello   2
 hello   3
 hello   4
 hello   5

Any statements in the block from do to end are repeated with different values of the variable i.

Spacing and line ends (often called ‘whitespace’) is usually not important. This code could also be written like so:

 for i = 1, 5 do print("hello", i) end

or

 for i = 1, 5
 do
 print("hello",i)
 end

However, the last example would be considered bad style. The logic of a program is much easier to follow if statements are laid out at the right columns.

The numeric for statement loops from a start to a final value, inclusive. There can be a third number, which is the ‘step’ used in calculating the next value. To print the greetings out backwards:

 for i = 5, 1, -1 do print("hello",  i) end

So to print a little table of sine values from 0 to pi; with steps of 0.1:

 for x = 0, math.pi, 0.1 do
     print(x, math.sin(x))
 end

note

There is something you need to know about for variables; they only exist inside the block.

 for i = 1,10 do print(i) end
 print(i)

You might expect that the last value printed would be 11, but the last print will show just nil; i is not defined outside the loop.

Conditions

Programs often have to make choices.

 age = 40
 if age > 30 then
    print("too old to play games!")
 end

(Well, that’s rude, but computers often are. You can’t please everyone.)

The expression in the if statement is called a condition. For instance, 10 == 10 is always true; 2 >= 3 (meaning ‘greater or equal’) is always false.

Like Python and the C-like languages == is used for ‘is equal’, since a single = has a very different meaning. Unlike them, ‘not equal’ is ~= (the tilde ~ is usually the key on the far left side, next to !)

It is common to have two different actions based on the condition:

 if age > 30 then
     print("still too old")
 else
     print("hello, kiddie!")
 end

And there may be multiple choices:

 age = 18
 if age == 18 then
     print("just right")
 else
     if age > 30 then
         print("too old")
     else
         print("too young")
     end
 end

This style gets irritating if there are more than two conditions. if-else statements can be combined together using the single word elseif (not the two words else if!)

 age = 18
 if age == 18 then
     print("just right")
 elseif age > 30 then
     print("too old")
 else
     print("too young")
 end

Conditional expressions can be combined with and or or:

 a > 0 and b > 0 or a == 0 and b < 0

In this expression, > and == evaluate first, followed by and, and then or. So the explicit form would be:

 ((a > 0) and (b > 0)) or ((a == 0) and (b < 0))

The not operator turns true into false, and vice versa. Instead of saying age > 30 you can say not(age <= 30). The parenthesis is needed here because not has a higher precedence than <=; in fact it has the highest precedence of the logical operators.

Lua will ‘short-circuit’ logical expressions, For example,

 if type(n) == 'number' and n > 0 then .... end

n > 0 will give an error if n is not a number, but Lua knows that if the first argument of and is false, then there is no point in evaluating the second argument.

In general, if a condition is f() and g(), then if the result of calling f is false there is no need to call g. Simulary, in f() or g() Lua will not call g if f returns true.

and and or in Lua do not only return true or false. and always returns its second argument if both arguments pass, or the argument that does not pass. (Only nil and false fail a condition.)

 print (10 and "hello") --> hello
 print (false and 42) --> false
 print (42 and false) --> false
 print(nil and 1) --> nil

or will return the argument that succeeds (i.e not nil or false)

 print (10 or "hello") --> 10
 print(false or 42)  --> 42

This leads to some common shortcuts in Lua code. For example, this explicit statement for setting a default value:

 if x == nil then
     x = 'default'
 end

is often written like this:

 x = x or 'default'

A common pattern for choosing one of two values looks like this:

 a = 2
 print(a > 0 and 'positive' or 'zero or negative')  -- positive

if statements can be used inside the for statement:

 for i = 1,10 do
     if i < 5 then
         print("lower",i)
     else
         print("upper",i)
     end
 end

Generally any statement can be ‘nested’ inside any other statement.

Conditional Loops

This produces the same output as the simple for statement example:

 i = 1
 while i < 5 do
     print("hello",i)
     i = i + 1
 end

The body of the while loop is repeatedly executed while a condition is true; each time one is added to the variable i , until it becomes 6, and the condition fails.

The other loop statement is repeat, where we loop until a value is true.

 i = 1
 repeat
     print("hello",i)
     i = i + 1
 until i > 5

For these simple tasks, it is better to use a for statement, but the condition in these loops can be more complex.

Tables

Often we need to store a number of values in order, usually called arrays or lists.

Arrays in Lua are done using tables, which is a very general data structure. A simple array is easy to define:

 arr = {10,20,30,40}

and then the first element will be arr[1], etc; the length of the array is #arr. So to print out this array:

 for i = 1, #arr do print(arr[i]) end

(Arrays start with index 1; it’s best to accept this and learn to live with the fact; this corresponds with common mathematical notation anyway)

These arrays are resizable; we can add new elements:

 arr[#arr + 1] = 50

and insert elements at some position using the standard function table.insert ; the second argument is the index before where the value is inserted.

 table.insert(arr, 1, 5)

After these two operations the array now looks like {5,10,20,30,50,50}.

Arrays can be constructed efficiently using a for-loop. This creates an array containing the squares of the first ten integers:

 arr = {}  -- an empty table
 for i = 1, 10 do
     arr[i] = i ^ 2
 end

Please notice that it is not necessary to specify the size of the array up front; a table will automatically increase in size.

To complete the picture, there is table.remove which removes a value at a given index.

The function table.sort will sort an array of numbers in ascending order. !ex!

Lua tables can contain any valid Lua value:

 t = {10,'hello',{1,2}}

So t[1] is a number, t[2] is a string, and t[3] is itself another table. But do not expect table.sort to know what to do with t; by default it only sorts arrays that contain numbers or strings. Later we will see how to do a general sort.

What about trying to access an element that does not exist, e.g. arr[20]? It will not raise an error, but return the value nil. So it is wise to carefully check what is returned from an arbitrary table access. Since nil always indicates ‘not found’, it follows that you should not put nil into an array. Consider:

 arr = {1,2,nil,3,4}

What is #arr? It may be 2, but it will definitely not be 5. In other words, it is undefined. Since inserting nil into an array causes such a breakdown of expected behavior, it is also called ‘inserting a hole’.

The same caution applies to creating arrays that start at 0.

 arr = {}
 for i = 0,9 do arr[i] = i end

Well, arr[0] will be 0, and arr[9] will be 9, as expected. But #arr will be 9, not 10. And table.sort will only operate on indexes between 1 and 9.

So yes, it is possible to arrange arrays from 0, but the standard table functions will not work as expected.

It is possible to compare tables for equality, as we did above:

 a1 = {10,20}
 a2 = {10,20}
 print(a1 == a2) --> false !

The result is false because a1 and a2 are different objects. The Lua comparison operator does not compare the elements, it just checks whether the arguments are in fact the same tables.

 a1 = {10,20}
 a2 = a1
 print(a1 == a2) --> true !
 a1[2] = 2
 print(a2[2]) --> 2

a1 and a2 are merely names for the same thing – a2 is just an alias for a1.

Newcomers to Lua are often surprised by the lack of ‘obvious’ functionality, like how to compare arrays ‘properly’ or how to print out an array. It helps to think of Lua as ‘the C of dynamic languages’ – lean and mean. It gives you a powerful core and you either build what you need, or reuse what others have provided, just as with C. The whole purpose of this cookbook is to provide good solutions so you do not have to reinvent the wheel.

There is another use of Lua tables, constructing ‘dictionaries’ or ‘maps’. Generally a Lua table associates values called ‘keys’ with other values:

 M = {one=1,two=2,three=3}

M operates like an array with string indexes, so that we have:

 print(M['one'],M['two'],M['three'])
 --> 1   2   3

An unknown key always maps to nil, without causing an error.

To iterate over all the keys and values requires the generic for loop:

 for key, value in pairs(M) do print(key, value) end
 --> one     1
 --> three   3
 --> two     2

The pairs function creates an iterator over the map key/value pairs which the generic for loops over.

This example illustrates an important point; the actual order of iteration is not the original order. (In fact the original order is lost, and extra information needs to be stored if you want the keys in a particular order.)

Functions

It is straightforward to create your own functions. Here is a sine function which works in degrees, not radians, using the standard function math.rad for converting degrees to radians:

 function sin(x)
     return math.sin(math.rad(x))
 end

That is, after the keyword function there is the function name, an argument list and a group of statements ending with end. The keyword return takes an expression and makes it the value returned by the function.

Functions are the building blocks of programs; any programmer collects useful functions like cooks collect tasty recipes. Lua does not provide a standard function to print out arrays, but it is easy to write one:

 function dump(t)
     for i = 1, #t do
         print( t[i] )
     end
 end

A function does not have to return a value; in this case we are not interested in the result, but the action. It is not an error to assign this function to a variable; the variable gets a nil value:

 p = dump{10,20,30}  --> p is now `nil`
 -->
 10
 20
 30

This dump is not so good for longer arrays, since each value is on its own line. The standard function io.write writes out text without a line feed:

 function dumpline (t)
     for i = 1, #t do
         io.write( t[i] )
         if i < #t then io.write(",") end
     end
     io.write("\n")
 end

 dumpline({10,20,30})
 --->
 10,20,30

True to its name, most of this Cookbook is dedicated to giving you functions to do useful things, or pointing you to existing solutions packaged as easily available modules.

Next: Types

generated by LDoc 1.3