A Look at Lua

by Joseph Quigley
on June 1, 2007

Lua is a free and open-source multi-paradigm programming language releasedunder the MIT license. Created in 1993 by Roberto Lerusalimschy, LuizHenrique de Figueiredo and Waldemar Celes, Lua is a dynamically typedlanguage. Extremely compact (only 150KB compiled), it is primarily usedas a scripting language or an extension to another language (mainly C/C++).

What Is Lua and How Is It Used?

Lua is implemented as a library and has no “main” program. It worksonly when embedded in a host client. The interpreter is a C program thatuses the Lua library to offer a standalone Lua interpreter. Ratherthan provide a complex and rigid specification for a single paradigm,Lua is intended to be extended to fit different problem types.

Being small, Lua fits on many host platforms and has been ported andused in video games for both the PlayStation Portable and the NintendoDS, and it is used in larger games, such asFarCryandWorld of Warcraft. TheAdobe Photoshop Lightroom photography program and the lighthttpd Webserver have incorporated Lua as well. Lua has a few advanced features,primarily coercion, coroutines, garbage collection, first-class functionsand dynamic module loading. Because Lua is small, it includes only a fewdata types. It attempts to maintain a balance between power and small size.

What's Different about Lua?

Lua is comparably as easy as Python in terms of learning how to writecode. Of the two, Lua is usually the better choice for embedded systems,simply because it's smaller. Lua's strength is in processing stringsand tables. It handles logical equations more adeptly than Python.

For a quick hack, a Lua programmer can process complicated data morequickly and easilythan a Python programmer can (although a Ruby programmercan do so almost as quickly). But, for a large application that handlesmany chunks of complex data, a heavier language such as Ruby or Pythonmay be a better choice.

There is no need to worry about different types of integers. You mayhave found that the different types of integers and numbers (such asfloats, longs or doubles) can screw up the output of your program oreven make it crash if you are absent-minded. Lua uses coercion for everyinteger and number type to convert it into a single type. You can add afloat, long integer or a double to any other type of integer or numberwithout a hitch in Lua. In contrast, doing this can cause programs writtenin Python 2.4 or older versions to crash. Lua is extremely forgivingsyntactically. What if, for some reason, you are programming on anembedded device with a four-inch wide screen? You can reduce the amountof lines and other characters, which in turn enables easy reading of thecode to make up for the small screen.

Small is beautiful. A programmer can embed Lua into several otherlanguages, such as C/C++ and Java, without bloating the host language,because Lua has a tiny API. Similar to Lisp's single data structure,tables are the only data structuring mechanism that Lua has. This makestables very powerful, because with a little work, they can emulate datastructures in larger languages.

Object-oriented programming implementation is minimalistic. Lua usestables and functions rather than classes.

In contrast to Python, Lua does not focus on 100% backwardcompatibility. Many newer releases of Lua break programs written inprevious versions. Fortunately, the Lua developers always announce whatthe new versions of Lua will break.

Lua supports threading. Multiple Lua interpreters can coexist in thesame process, and each one can run independently in its own thread. Thisoften makes Lua desirable for multithreaded programs in embedded systems.

Installing Lua

To compile and install Lua from the source code, grab a copy of Lua5.1 from the Lua.org Web site, and untar, configure, make andinstall it:

tar -xvzf lua-5.1.1.tar.gzcd lua-5.1.1makexyz makexyz install

(xyz is your platform name.)

Lua should now be installed and working. To test your install, typelua on the command line. An interactive interpreter should appear.

Syntax

Lua is a dynamically typed language whose syntax is very similar to thatof Python and even more similar to Ruby. Line breaks do not play anyrole in Lua's syntax, like that of Python or Ruby. Take, for example,the following ugly, but valid code:

foo = 89bar = foo+2print(bar)

Because it is small, Lua has only eight basic data types:

  1. nil (similar to Python's None)

  2. booleans

  3. numbers

  4. strings

  5. functions

  6. userdata (a type that allows arbitrary C data to be storedin Lua variables)

  7. threads

  8. tables

Lua supports only a fewdata structures, including arrays, lists and hash tables.

The table type implements an associative array that can be indexed withany value (similar to Python), except nil (dissimilar to Python). Nil'sgoal is to be different from any other value, as well as the default valuefor global variables. Nil also plays a much more important role in Luathan None does in Python. Although tables are the only data structuringmechanism in Lua (which may seem like a disadvantage), the table is justas powerful as Python's dictionary and list, and it's even as powerful as Ruby'shash. Tables are used to represent many different types of arrays, sets,trees and several other data structures. One handy feature of tablesis to use strings as keys—for example:

x = { ["hello world!"] = "ciao world!" }print(x["hello world!"])

When running this example, Lua outputs “ciao world!” and not“helloworld!” as it might appear.

For a more in-depth look at Lua's tables go tolua-users.org/wiki/TablesTutorial.

Variables and Identifiers

Because any value can represent a condition, booleans in Lua differ fromthose in many other languages. Both false and nil are considered falsein Lua, but Lua considers everything else true (including zero and anempty string).

Unlike Python, global variables do not need to be declared. To create one,assign a value to it. To delete it, give it the nil value. A globalvariable exists only if it has a non-nil value. Exactly the oppositeof Python, most variables in Lua are global by default, and you mustdeclare the variable “local” to make it a local variable rather thanassuming that all variables are local.

Because most CPUs perform floating-point arithmetic just as fast asinteger arithmetic, numbers in Lua represent real, double-precision,floating-point numbers rather than common integers. Because Lua doesn'tneed integer types, it doesn't have them. This eliminates rounding errors,floating-point numbers and long integers.

Lua handles strings very adeptly and has been used for strings thatare several megabytes long. It converts between strings and numbers;any numeric operation applied to a string converts the string toa number. This conversion principle applies only to numbers, asLua converts numbers to strings when strings are expected. Even withautomatic conversion, Lua still can differentiate between numbers andstrings in cases like 90 == “90” (which always is false).

Identifiers starting with an underscore (such as _FOO) are not recommendedfor use in Lua, because many are reserved for special uses. As long asan identifier does not begin with a digit, the identifier can be madeup of a combination of underscores, letters and digits.

You can basically rename anything in Lua, even to the point of makingit un-callable. Take, for example, the following code:

x = iox.read()io = "Hello world!"x = "Let's make io uncallable!"io.read()

The second line gets keyboard input through the io module. Becauseio is essentially a variable with a function as a value, you can give it adifferent value so that io does not relate to the input/output functionsanymore. When you try to get keyboard input from the io module again,Lua returns an error. The program is unable to call the input/outputfunctions now that io's value has been reassigned. In order to use io again,you must restart the Lua program.

Operators and Assignment

Lua concatenates strings with the .. operator. Note thatprint("Hello".."World!") is valid, butprint("I've said'Hello World'"..5.."or more times.") is not. This is because Luasees the periods as decimals after the integer. The operator must havea space between the strings and the integer. Otherwise, it won't returnan error. The following code validly concatenates the strings and theinteger:

print("I've said 'Hello World' " ..5 .. " or more times.")

Lua uses many of the common operators that Python, Ruby and most everyother language use. For the Python/Ruby logical not operator, Lua caneither use it or use ~= for the negation of equality. Always rememberthat Lua treats strings and integers differently:"1" <2 is always false,and strings are compared alphabetically.

Lua ends while loops if the condition is false. Repeat-until statementsare the opposite of while loops; they loop until the condition istrue. for loops have some hidden twists, which can be annoying to Pythonor Ruby programmers. Local variables created in the for loop are visibleonly inside the loop. The variable does not exist when the loop ends,so if you need the value of the control variable, you have tosave its value into another loop. Breaks or returns should appearonly as the last statement before an end, an else or an until in a loop forsyntactic reasons.

Lua treats functions as “first class” values and uses them forOOP (object-oriented programming). Lua can call its own functions or C functions, and it handlesfunctions as a type. You can give a variable the function propertyor create it with the function() method. Functions written in Lua canreturn multiple results if you list them after a return keyword.

Lua supports OOP, but due to Lua's size,its implementation of OOP lacks a few features. Lua uses tables andfunctions for OOP rather than classes. In the same way that Pythonaccesses a function or variable in a class, Lua accesses it withTable.function or Table.variable.

Lua can be picky when it comes to multiple assignment, because it adjuststhe number of values on the assignment. If the amount of values is lessthan the list of variables, all remaining values are given the nilvalue. If the list of values is longer than the amount of variables,Lua silently discards them.

Object-Oriented Programming

Lua has some basic OOP capabilities. The self parameteris an integral concept in any object-oriented language, and it is one ofthe few OOP concepts that Lua has. Many object-oriented languages tendto hide the self mechanism from you so that you do not have to declarethis parameter. Lua hides this parameter with the colon operator. You also can use the colon, a function and a table to emulate a class. BecauseLua does not have the class concept, each object defines its own behaviorand shape:

Earth = {martians = 5389}function Earth:casualties (survivors) Earth.martians = Earth.martians - survivors print("Earth is free! "..Earth.martians.." martians survived!")endEarth:casualties(5380)

The colon in the above example is used to add an extra parameter in themethod definition. It also adds an extra argument in the method call. Youdon't have to use the colon. Lua programmers can define a function withthe dot syntax and call it with the colon syntax, or vice versa if theyadd an extra parameter:

Earth = {martians = 5389, casualties = function (self, survivors)  self.martians = self.martians - survivors  print("Earth is free! "..self.martians.." martians survived!") end}Earth.casualties(Earth, 5380)Earth.martians = 5389Earth:casualties(5380)

In this case, the function had to be part of the table so that it could becalled via the dot or the colon syntax. Note that I also had to give thefunction the self parameter for either calling method to work. Althoughthese are simple OOP examples that scratch only the surface of OOP, youcan find out about inheritance and other OOP implementations in the LuaReference Manual or in the bookProgramming in Lua (both are availablefor free from the Lua Web site).

Show and Tell

Now, let's compare programming in Lua to programming in Python. First,let's write a trivia game. Here is some simple Lua code that uses a tableas a dictionary to store both the questions and the answers:

print("What's your name?")name = io.read()questions = {  ["Which came first? Minix or Unix?"] = "Unix",   ["Who created Linux?"] = "Linus Torvalds",  ["In what year was Linux created?"] = "1991"}correct_answers = 0for key,value in pairs(questions) doprint(key)answer = io.read()if answer == value then  correct_answers = correct_answers + 1endendif correct_answers == 0 thenprint("You need to browse Wikipedia!")elseprint("\nGood job, "..name.."!")print("Correct answers: "..correct_answers..")end

Next, let's break it down and analyze it line by line. On the second line,the variable name is given the value io.read(). The iolibrary has many functions that handle all sorts of input and output,but I'm using it only for keyboard input.

On the next line is the variable questions. The questionsvariable's value is a table that I have used like a dictionary to storeboth the questions and the answers. The questions are in brackets totell Lua that they are the table's key.

Skipping the third line, there is a for loop whose function hereis to use pairs() to find the key and the values of each item in thetable. It then needs to place the value of the key and the value of thekey's value into the variables key and value.

After printing the key (which contains the question), Lua places theuser's answer through io.read() into the answer variable and checks tosee whether it equals the proper answer. If the answer is correct, it adds 1to the value of the correct_answers variable and repeats the processuntil there are no more items in the table to go through.

Next, Lua checks to see whether users got any of the questions correctand then prints a message telling users to learn more about UNIX(and its variants) hacker history or congratulates users on how manyquestions they answered correctly. Notice the concatenation operators onthe 16th line.

In Python, the easiest way to do the above game would be like this:

name = raw_input("What's your name?\n")questions = {"Which came first? Minix or Unix?":"Unix","Who created Linux?":"Linus Torvalds","In what year was Linux created?":"1991"}correct_answers = 0for key in questions:  print key  answer = raw_input()  if answer == questions[key]:    correct_answers += 1if correct_answers == 0:  print "You need to browse Wikipedia!"else:  print "\nGood job, " + name + "!"  print "Correct answers: ", correct_answers

You may notice that it's easier to get keyboard input in Python than inLua, but dictionaries are easier to identify and look much prettier inLua. The for loop is a little more complex in Python than it is in Lua, becausePython needs to know the key to be able to get the key's value. InLua, the pairs() function breaks apart the key and its value from thedictionary table, making it much cleaner and easier to get data from tablesthan in Python. As for lines of code, not counting the many“ends”, Luawins hands down with 13 lines of code versus 17 in Python. Even thoughLua programmers would be typing more, their code is much easier to siftthrough, especially when it's thousands of lines long, because of Lua'suse of end rather than colons (as in Python).

Now, how about a GUI? Is programming a GUI in Lua the same, easier ormore difficult than in Python? Before you try to answer that question,determine which program in the two languages will be easierto maintain, read and understand without comments. Here, I usethe WxGTK library for a GUI. The only hitch with wxLua is that it isan entirely separate program. A wxLua application will not run with theregular Lua interpreter, so you must run it with thewxlua program.

Here's a GTK GUI program made with wxLua:

frame = wx.wxFrame(wx.wxNull, wx.wxID_ANY,   "wxLua App", wx.wxDefaultPosition,   wx.wxSize(250, 50),  wx.wxDEFAULT_FRAME_STYLE)frame:Show(true)

Now, here's the code for a program that does the same job in GTK, butwith wxPython:

from wxPython.wx import *class Main(wxApp):  def OnInit(wxApp):    frame = wxFrame(NULL, -1, "wxPython App")    frame.Show(true)    return trueMain().MainLoop()

This time, Lua's lack of necessary formatting and full-fledged OOP makesan easy job easier. Rather than create a class and function, wxLuaincorporates everything needed for this GUI application in a singlesystem function, whereas Python and wxPython require a Class as well as afunction. Also note that Lua imports system libraries automatically. ThiswxLua application exercises some of Lua's OOP features that I discussedpreviously. The application creates the frame, sets the frame's nameand the frame values, and then it calls the Show() function from within thewxFrame method using the colon. You also can call the frame with theperiod syntax rather than the colon:

frame.Show(frame, true)
Embedding and Extending

Although taking a look at embedding and extending Lua is outside thescope of this article, I touch on a few concepts here. First, theLua API is very straightforward. Its design eliminates the need formanual reference when embedded in C code (unlike Python's API). Likethe language, Lua's C API (for embedding) is fairly minimalistic. Ifyou need advanced functionality, you can use a secondary library thatis primarily made up of preprocessor macros.

Second, C and C++ are not the only languages in which Lua can be embedded. Tao.Lua provides straight .NET and Mono bindings to Lua, and LuaJavaallows scripts written in Lua to manipulate Java components. LuaJavaallows Java components to be accessed from Lua with the same syntax thatLua uses for accessing its native objects. It also allows Java to use aLua interface so that any interface can be implemented in Lua and passedas a parameter to any method. The method's result (when called in the Javaprogram) is called in Lua, and the result is sent back to Java.

Conclusion

Lua is a flexible, powerful, compact language that can be used andextended in myriad situations. Its focus on simplicity makes foreasy debugging and has attracted many users. Its simple, powerfulsyntax provides flexibility because of Lua's metamechanisms. Thesmall, fast interpreter uses less resources than Python, and its syntaxallows for easier code readability. Its simple C API makes embedding abreeze. Whether you are doing data processing, GUIs or game programming,you will find a use for Lua.

Joseph Quigley has been a Linux user for more than two years. He enjoysfiddling with different Linux distros and exploring new programminglanguages.

Load Disqus comments