Page 1 of 1

Introduction to Lua - Part II tables, tables, tables!

#1 KYA  Icon User is offline

  • g++ jameson.cpp -o beverage
  • member icon

Reputation: 3101
  • View blog
  • Posts: 19,141
  • Joined: 14-September 07

Posted 10 April 2009 - 03:48 PM

Introduction to Lua - Part II

If you haven't familiarized yourself with Lua, please read: Introduction to Lua. This tutorial assumes you have a basic understanding of Lua, have it set up to run on your system, and perhaps a little bit of prior programming experience/knoweldge. Having that said, let's get started:

Tables in Lua

A table is the only native data structure in Lua. I say native because userdata can import data and structures from C so, in concept, there are an infinite amount of possibilities there, but for the sake of this tutorial we're only focusing on tables.

Tables can represent nearly any structure you'd see in another language: stacks, queues, arrays, vectors, etc... How does it do all of that you ask? Well it really doesn't. It does what the programmer tells it to. Neat huh? How can you tell if a variable is a table? From context:

--regular variable
a = 5

--a table is denoted by '{}'
a = {}	-->a is now an empty table



If you've had experience with any of the C style languages you'll immediately see the ability to use a table as a traditional array:

--table as a traditional array
a = {1,2,3,4,5}
for i = 1, #a do
	print(a[i])
end



Important: #tableName denotes the length of the table '#'

Remember that tables are generally indexed starting at 1 in Lua. While you may change this, many plug ins, libraries, etc.. keep this "starting at 1" standard. I recommend you do the same.

So far this doesn't appear to be a big deal, since we are operating within traditional boundaries. Consider the following snippet:

k = "x"
a[k] = 10
print(a[k]) 					--> 10
a["name"] = "The Table"
print(a["name"])				--> "The Table"



I'll give you a minute to go find your socks; the ones that were just blown away. A table has two very important properties. Keys (the "index") and the value associated with it. Keys can be anything, numbers, letters, strings, etc... Anyone familiar with STL/C++ will see this is incredibly similar to the STL Map, which has two values, a key and then the associated value.

Important: A table is Lua is an associative array. It can be indexed with anything except 'nil'. We'll see why in a minute. Tables have no fixed size, you can add as much as you want. Lua uses tables to represent modules, packages, etc.. so when you use the input read:

input = io.read()



It means, "index the table 'io' using 'read' as the key". This is a bit outside the scope of the tutorial, but helpful to know.

Important: Tables are not variables, nor values. They are objects. Anyone with a Java background will immediately relate to this given that arrays in Java are objects as well. Tables are dynamically allocated objects. Good news for prior programmers: there are no hidden copies or behind the scenes garbage going on with tables. WYSIWYG.

Manipulating Tables

To erase a value in the table you assign it to nil. If you try to access it again after erasing it, you will get a nil output. Consider the following:

--To erase values, assign them to 'nil'
a = {}
k = "x"
a[k] = 10

print(a[k])						--> nil
a[k] = nil						--> "deletes" this entry in the table
print(k)						--> k is still "x"
print(a[k])						--> nil
print(a["x"])					--> nil




We make a variable 'k' whose value is 'x'. (Stay with me on this one). We then make an entry in table 'a' at index 'x' whose value is 10. (Still there?) We then assign the index of 'x' in a to nil, thereby erasing it. I printed 'k' to show you that that variable is not changed by that action, however trying to access 'a' at 'x' results in nil, in both methods. Now, if you aren't thoroughly confused yet, check out this snippet:

a = {}
k = "x"
a[k] = 10

print(a[k])						--> 10
k = nil						--> assign k's value to nil
print(k)						--> k is now nil
print(a[k])						--> nil, there is no indexing with a value of nil
print(a["x"])					--> 10, as this object in the table still exists



We assigned k's value to nil and as mentioned, cannot index a table with nil. The index at 'x' still exists though and correctly prints out 10.

Clear as mud? Don't worry, it takes a while. Mainly because (and I am in this group) coming from strongly typed languages and only integer indexed arrays, this flexibility is unprecedented.


Passing by...?

C++ has the ability to pass by both value and reference, java just by value. Consider a table a set of references you access through various indexes. You do not need to worry about such access when passing tables around your functions. An example:

function tableStuff (table)
	if #table < 1 then
		print("Table is rather empty!")
	else
		for i = 1, #table do
			print("Index: " .. i .. "  " .. table[i])	-->string cat is '..' not '+'
		end
	end
end

--example usage
a = {}
tableStuff(a)
b = {1,2,4,5}
tableStuff(b)



Output:

Quote

Table is rather empty!
Index: 1 1
Index: 2 2
Index: 3 4
Index: 4 5


String concatenation is '..' rather then the traditional '+', more on this in later tutorials. Notice that we check to see if the length of the parameter passed is at least one or greater. This is also a rudimentary table check. If the variable passed in is not a table, we do not want to try to iterate through it. For example:

function tableStuff (table)
	if type(table) ~= "table" then
		print("Param is not a table!")
	else
		for i = 1, #table do
			print("Index: " .. i .. "  " .. table[i])	-->string cat is '..' not '+'
		end
	end
end

--example usage
a = 5
tableStuff(a)
b = {1,2,4,5}
tableStuff(b)



Output:

Quote

Param is not a table!
Index: 1 1
Index: 2 2
Index: 3 4
Index: 4 5


Remember! Indexes with "x" and x are not the same. One is a string and the other is the variable x. Consider the following:

a = {x=10, y=20} --same as a = {} a.x = 10 a.y = 2
print(a.x .. " " .. a.y)



The above table is indexed with two strings "x" and "y". If we try to access the object at x thinking its the same:

a = {x=10, y=20} 				--> same as a = {} a.x = 10 a.y = 2
print(a.x .. " " .. a.y) 		-->a.x = a["x"] a.y = a["y"]

print(a[x])						-->nil



As mentioned in the very beginning, a table is noted with the constructor {}, we can create complex data structures using nested constructors and some imagination:

--A more complex table:
employees = {company = "Microsoft", department = "Software Dev",
				{name = "Knowles Atchison", age = 21},
				{name = "Bob Smith", age = 43},
				{name = "Julie Brown", age = 27}
			}
--> employee table for Microsoft's Software Dev. department

print(employees.company .. "'s " .. employees.department ..
			" department employees: ")

for i = 1, #employees do
	print(employees[i].name .. " " .. employees[i].age)
end



Output:

Quote

Microsoft's Software Dev department employees:
Knowles Atchison 21
Bob Smith 43
Julie Brown 27


Remember! tableName.index is equivalent to tableName["index"] You can also broadly assign a table to another table, no overloading operator needed!

a = {1,2}						   --> a is a table
b = a					   --> b is assigned to what 'a' has
print(b[1] .. " " .. b[2])		  --> 1 2, a's values that b now has





As you can see, we have barely scratched the surface on all the various things we can do with tables. Hopefully you found this tutorial both informative and interesting. I think part III will pertain to functions. Happy Coding!

--KYA

Is This A Good Question/Topic? 0
  • +

Page 1 of 1