Variables

<< Commenting | Lua | Functions >>

Variables represent a memory inside a program comparable to the our own memory.

Unlike in other progamming language, there's no need in lua to declare variables (but you can change this behaviour if you don't like it).

Simply use a variablename that you need:

Example:

myvariable="hello"
print(myvariable)
myvariable=123
print(myvariable+10)

Output:

 hello
 133

A variable in Lua is just a name, the type is set dynamicly to whatever you use the variable for. There are only 6 different types in lua:

  • boolean (true or false)
  • numbers (no matter with or without point etc.)
  • strings
  • tables
  • threads (Co-routines)
  • userdatas

A special value here is nil. A variables that become nil will stop existing.

You have seen numbers and strings by now, let's take a quick look at the other types. Userdatas are dataelements that are created by the implementors side of Lua, so Luxinia for example.

Every object in Luxinia that you touch is a userdata value and most functions in Luxinia need a userdata value as argument. Userdatas can have metatables, but you cannot modify them directly. I will come back to metatables and what this means in a later tutorial, but not for now since metatables are an advanced topic.

Threads are coroutines in Lua. Coroutines can be created from functions in Lua and can be used for a multitasking like behaviour. Coroutines, once run, will run until they finish or a yield is called which then returns to the line where the coroutine was invoked. The function can then be continued at any time. Coroutines are usefull if you want to process something that takes long and you want to split this task up in several small parts that are processed frame by frame. This is needed if you want to show the user a loading screen telling him how much must be loaded for example.

Strings and numbers

Strings and numbers are very simple types and I don't need to explain much about it (although there's much more to be said about it, but I don't want to get this tutorial too long). Strings describe texts. A string can be of any length. Strings cannot be altered - you cannot change the value of a single sign in the string, you can only make copies. This is the reason why you shouldn't concatenate strings to longer and longer strings, since evertime a copy is made and that needs much memory and performance. Instead, you should push the strings in a table and call table.concat. That will create one big string from all the entries in the table in an optimized way. It is often the case that beginners don't know this and wonder why their code is slow.

Numbers are describing numbers (surprise!), unluckyly, numbers in computers are somewhat limited in precission and "size". Numbers in lua are always floating point numbers. There are no integers (integers have always rounded values). If a function in luxinia says it wants an integer value or anything like that, just pass a number. The precission of numbers in lua are dependend on the way the programmers integrate lua, in our case we use the default type and that are double values (doubles are normally 64bit sized). Double values can become fairly large and offer a good precission. We decided to leave it this way although luxinia is using only 32 bit floating point precission.

Conversion

Numbers and strings are converted to each other if needed and if possible.

Example

print("1"+"2"+3+4)
print((1)..(2).."3")

Output

 10
 123

The numbers in the second line must be in round brackets, otherwise the compiler will complain about the numberformat.

However, it is often better to convert a variable into a string before using it as a string:

Example

x = 2
print(tostring(x))

Output

 2

The other types cannot be converted into each other.

Naming variables

You can choose any name for a variable as long as it starts with a letter and doesn't contain special signs except underscores. Valid names are
  • mytable
  • my2ndtable
  • MYtable?
  • next_number
  • _myvar
Watch out here that the names are case sensitive, so MYtable? is another variablename than mytable.

Invalid names are

  • 42names
  • my-bottom-line

Assigning values

As seen before, you can assign values to variables by using a equal sign:

 hello = 3 
You can also assign multiple variables at once:

Example

 a,b,c = 1,2,3 
print(a,b,c)

Output

  1  2  3 

This looks strange to programmers that come from languages that are like C or Java. But it is usefull:

Example

a,b = 1,"hello"
a,b = b,a
print(a,b)

Output:

 "hello"   1

We exchanged here the values of a and b without using a temporary variable.

What cannot be done is a usage like this: a = b = 3.

Scope

When a varible is initialized, it is per default stored in a global table that everyone can access (normaly).

A scope is declared in different ways. We will just take a look at the do ... end case where the scope is limited from do to end

A scope is a kind of view: You can declare variables to be only "visible" within a certain range and that is your scope.

If you don't want to share a variable with other pieces of code, you need to declare the variable as local:

Example

do
  aglobalvalue = 3
  local alocalvalue = 1
  print("my local value: ",alocalvalue)
  do 
    local aglobalvalue = 10
    print("my global value, now local: ",aglobalvalue)
  end
end
print(aglobalvalue,alocalvalue)

Output

 my local value:   1
 my global value, now local:  10
 3,nil

It is always a good idea to declare a variable as local. It allows a faster access on the value of the variable. It is also annoying if you pollute the global variable table with lot's of names that other parts of lua code are absolutly not interested in.

As you can see above, local variable names will not change global variables. They will coexist and you cannot access the global value with the same name, once you are using a local variable of the same name. But when the scope is leaved, the global value can be accessed again normally.

As said above, a do - end block is only one type of scope. There are other forms that provide their own scope.

Tables

Tables are the most important datastructure in Lua. You can imagine tables as real table where each line can by found by using a name or a number.

This name can be of any type (strings, numbers, tables, coroutines, userdatas) and there is only one line per name, this is why this is often called 'key' - you can adress any value in a table if you got the right key. Let's do an example:

Example

mytable = {}
mytable[1] = "hello"
mytable[2] = "second table value"
mytable[249043] = "the key can be any value"
mytable["akey"] = "a key can be a string..."
mytable.anotherkey = "and can be adressed this way, too"

This is a simple table, initialized one by one. You could write it in a shorter form this way:

Example

mytable = {
  "hello", "second table value",
  249043 = "the key can be any value",
  akey = "a key can be a string...",
  anotherkey = "and can be adressed this way, too",
}
note that you can leave the last comma out, but it doesn't hurt if you write one. You will like this little feature once you generate Lua tables automated as strings.

Garbage collection

Lua implements a garbage collection, that means that if you "forget" a variable, it will be removed from the memory automaticly. Don't be afraid now - it won't collect your variables if you still need them.

The garbage collection is done automaticly from time to time (it can be forced by calling collectgarbage()) and it will collect every variable that is no longer accessible.

For example:

mytable = {1,2,3}
mytable = nil

my2ndtable = {1,2,3}
backup = my2ndtable
my2ndtable = nil

The variable mytable cannot be accessed anymore since there's no other variable pointing to it. The 2nd table that was initialized is not removed since the backup variable is still pointing on it.

Even special cases like this are found and will be collected:

Example:

table1,table2 = {},{}
table1.tab = table2
table2.tab = table1
table1,table2 = nil,nil

Even though the tables are pointing at each other, the collector will recognize this and will collect it.

Values, pointers, references, adresses

A variable can hold a value, but the value can be of different type (seen above) - but not only in it meaning, but also in it's type of use.

Let's see

Example

a=1
b = a
a = 2
print("a = ",a,"b = ",b)

Output

 a = 2  b = 1

That shows that we haven't changed the value of b by changing the value of a. This is the same for strings.

But it is different for tables:

Example

 orig = {1,2,3}
table2 = orig
orig[1] = 7
print("table2[1] = ",table2[1]," orig[1] = ",orig[1]) 

Output

 table2[1] = 7  orig[1] = 7

What happend here is following:

  1. A table is created in memory of the computer
  2. A variable named orig is pointing to the memory adress
  3. The value of the variable orig is assigned to a variable named table2
  4. The value of the table at index 1 in memory is changed to 7
Both variables are pointing to the same table. That is what happened. Assigning table values to variables will not make a copy of the table. Only the adress to the table is here copied. So changing the table itself does not affect any variable at all - our variable just tells us which table should be used.

This mechanism has often different names like references or pointers, each one has different meanings in different programming language although the idea is the same: We use an address to a value, instead the value itself.

I will come back on that in the tutorial about functions.