Lua Introduction

From OpenEUO
Revision as of 15:42, 9 October 2010 by 76.184.213.234 (Talk) (Conclusion)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

This tutorial will focus on the new language Lua and assumes that you already know how script writing and programming works in general.

However, if you have never written anything besides scripts then some of the explanations may be a bit complicated. I suggest you just read on, look at the examples and try to figure out what they mean. If you still feel completely lost then don't worry, it will come in time as you get more used to Lua.

Variables and Types

You may leave this lesson out if it's too complicated and move on to the next part!

Variable names are the same as in other languages, a leading A-Za-z_ followed by any number of A-Za-z0-9_ characters. They are case sensitive, so X and x are not the same.

Variables are dynamically typed. That means, a variable can contain any type. Variables do not have types, values do.

Primitive types: number, string, boolean, nil (there are more types but I'll leave them away for now)

Numbers are always floating-point Doubles in Lua. Any Double can easily represent an Integer, so don't let that confuse you. Working with Doubles is just as easy as working with Integers.

Strings can be defined using double quotes "" or single quotes ''. Both are exactly the same (even when using escape sequences). You can concatenate two strings using the .. operator. It also works with a string and a number, in that order.

Booleans can be true or false. Use them in comparisons.

Nil is a special value/type which means "I'm not a value". It's often used by functions to return a value that signals an error. Undefined variables automatically have the value nil.

MyVariable1 = 2.14 + 1
b = "hello\nworld"
c = 'hello' .. '\nworld ' .. 123
d = x==3 or y<=7 and not z~=(7-4/2)*3
e = nil

In the above example, you also see lots of operators being used. They're mostly the same as in other languages, except for ~= which means "unequal". Operator precedence works as you would expect.

Assignments and Functions

The second half of this lesson may be a bit complex. Try to learn how to assign values to variables and how to create and call functions! Remember you can use print() to check results!

This is actually not as simple as it seems. Lua uses the idea of stacks extensively and thus can deal with long lists of values quite easily.

x = 1 --line comment
y = 2
x,y = 1,2
a,b,c = 1,2,3,4 --4 is ignored
a,b,c = 1,2 --c is assigned nil

As you can see, you can assign multiple variables in a single assignment statement. In mismatched situations, excess values are ignored and excess variables are assigned nil.

This feature really becomes useful for returning multiple values from a function, which is not possible in most other languages except by passing additional return variables as parameters or by using return structures.

function Test(a)
  return a*a, a^3
end

a,b = Test(5) --a=25, b=125

Actually, functions are another type in Lua. The above declaration is just a nice way of writing the following...

Test = function(a)
  return a*a, a^3
end

...which means there is a variable Test with (the address of) a function as value. It's similar to other languages that allow function pointers/references.

function Sum(a,b)
  return a+b
end

Diff = function(a,b)
  return a-b
end

function CalcInc(f,a,b)
  return f(a,b)+1
end

x = CalcInc(Sum,5,3) --x=9
y = CalcInc(Diff,5,3) --y=3
z = CalcInc(function(a,b) return a*b end,5,3) --z=16 using anonymous function

Parameter passing is always by value. Inside a function, passed parameter names have local scope, so they won't conflict with outside variables. You can also define local variables yourself.

function Square(a)
  local b = 123
  return a*a
end

a = 5
b = 5
x = Square(3) --x=9, a and b are still 5

In fact, all variables are global unless defined as local. Defining a local variable outside of a function or block means the variable is local to the file and can't be accessed from other files.

local function Sum(a,b)
  return a+b
end

local Sum = function(a,b)
  return a+b
end

The same goes for variables that contain functions. The above function declarations are the same. Both are local to the file so there won't be conflicts with other files or libraries.

Don't try to call functions that are defined later (i.e. further down). It's really just like with variables.

Control Structures

This lesson is a must read and should be quite easy to get!

Control structures are mostly the same as in other languages.

if x<y then
  --true
else
  --false
end

if x==1 then
  --case 1
elseif x==2 then
  --case 2
else
  --other cases
end

Note that IF must _always_ be terminated by an END, even if only one statement follows. This goes for all control structures and is a little inconvenient but you'll get used to it.

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

for i = 10,1,-1 do --step value is -1
  local x=1
  print(i-x)
end

Each block has its own local scope. So if you declare local variables inside a block, it will disappear if you leave that block (even if only for another iteration). FOR variables are automatically declared local.

repeat
  --do something
until x>10

while x<=10 do
  if x==7 then
    break
  end
end

do
  --simple block
end

You can use BREAK to jump out of REPEAT/WHILE/FOR structures. By definition, BREAK can only occur before an END keyword which seems a little odd at first but usually works out that way (any following statements couldn't be reached anyway).

Unfortunately, there is no CONTINUE. You must use nested IFs instead which is inconvenient as well but we'll just have to live with it.

--this won't work, there is no continue!!!
for y=1,20 do
  if y==10 then continue end
  for x=1,80 do
    if x==40 then continue end
    --do something (except when: y=10 or x=40)
  end
end

--use nested ifs instead
for y=1,20 do
  if y~=10 then
    for x=1,80 do
      if x~=40 then
        --do something except when y=10 or x=40
      end
    end
  end
end

There is also a FOR..IN statement that is used like a "foreach" in other languages. I'll cover that one later.

SWITCH isn't supported either but can be emulated using keyed hash tables and anonymous functions.

Tables

Ignore this lesson is you had problems with the previous ones. You won't need tables or arrays for basic scripts!

Tables really deserve their own tutorial because the topic is extensive! I'll just show you the basics here. And just like functions, tables are another type in Lua.

a = {22,84,63}
print("Num: " .. a[2]) --prints 84

a = {3.14,"test",true,MyFunc}
--tables can hold all kinds of values...

--...even other tables
a = {{"1","2"},{"3","4"}}
print(a[2][1]) --prints 3

a = {} --empty table, not the same as nil!

If you use a table like an array as shown above, indexing starts at 1 (unlike C++/Java etc where indexing starts at zero). The # operator tells you how many (numbered) elements there are in a table.

a = {"aaa","bbb","ccc"} --#a is 3
for i = 1,#a do
  print(a[i])
end

But tables are not just arrays, they can do a lot more. They're actually hash tables with key/value pairs. That means you can use any value as index, not just numbers. You give it a key, it tells you the associated value.

a = {
  [1] = "aaa",
  [2] = "bbb",
  [3] = "ccc"
} --same array as in last example

a = {
  ["a"] = "aaa",
  ["YouNameIt"] = "bbb",
  [3.14] = "ccc"
}
print(a[3.14]) --prints ccc

a = {[7]="num",["7"]="str"}
print(a[7]) --prints num

If you don't specify a key when defining a table, incremental numeric indices will be used which is why you can use tables as arrays. You can also mix, i.e. specify keys for some values and not for others. Unlike traditional arrays which have a fixed number of elements, tables also allow you to insert new elements.

a = {}
a[4] = "ddd"
a[5] = "eee"

So you don't need to declare everything inside {...}, it's just a nice way of doing it. But you must set the type of a variable to "table" by using at least {}. You cannot index a nonexistent table. When you access a nonexistent element, nil is returned. So deleting means setting an element to nil. It's the same as with variables. However, be careful when using the # operator on mixed tables that contain nil elements. You might get unexpected results.

Btw: When using valid identifiers as keys, you can also specify them directly (leaving away enclosing brackets and string markers) and use a dot to index in an object-like manner:

t = {id3 = 3}
print(t.id3)

--is the same as...

t = {["id3"] = 3}
print(t["id3"])

The enclosing brackets are really only there to allow prior evaluation of the index so that something like t["id"..3] becomes possible, but with simple identifiers it's not necessary.

There is a lot more to tables: A table library with more utilities, tables used as objects, metatables that define how values are accessed etc...

Conclusion

Still with me? Understood some of the examples? Great! Lua is a wonderful little language with many quirks and sometimes tricky besides. But you can also write very plain and simple code. Keep to the basics at first and move on to more difficult Lua concepts when you feel secure!

External links of interest:

First Steps

Hello World