Lua is Portuguese for moon. I had come across the word when browsing the web about programming languages, e.g. Free Compilers http://www.idiom.com/free-compilers/, Review of existing languages http://www.tunes.org//Review/Languages.html, Dictionary of programming languages http://cgibin.erols.com/ziring/cgi-bin/cep/cep.pl, The Language list http://cuiwww.unige.ch/langlist/, and Webopaedia http://webopedia.internet.com/Programming/Programming_Languages/.
I had paid it no attention till I read an announcement that Reuben Thomas had ported Lua 3.2 to RISC OS - see http://www.cl.cam.ac.uk/users/rrt1001/.
The purpose of this article is to give a brief, non-technical sketch of the ideas behind the Lua package.
The official description says:
"Lua is a powerful, light-weight programming language designed for extending applications. Lua is also frequently used as a general-purpose, stand-alone language.
"Lua combines simple procedural syntax (similar to Pascal) with powerful data description constructs based on associative arrays and extensible semantics. Lua is dynamically typed, interpreted from bytecodes and has automatic memory management, making it ideal for configuration, scripting and rapid prototyping.
"Lua is a language engine that you can embed into your application. This means that, besides syntax and semantics, Lua has an API that allows the application to exchange data with Lua programs and also to extend Lua with C functions. In this sense, Lua can be regarded as a language framework for building domain-specific languages.
"Lua is implemented as a small library of C functions, written in ANSI C, and compiles unmodified on all known platforms. The implementation goals are simplicity, efficiency, portability and low embedding cost. The result is a fast language engine with small footprint, making it ideal in embedded systems too.
"Lua was awarded the first prize (technological category) in the Second Compaq Award for Research and Development in Computer Science in 1997. This award was a joint venture of Compaq Computer in Brazil, the Brazilian Ministry of Science and Technology, and the Brazilian Academy of Sciences.
"Lua has been used in many different projects around the world. For a short list, see http://www.tecgraf.puc-rio.br/lua/uses.html."
These uses are varied and interesting: games, distributed business software, CGI scripting, snowmobile bench-testing... The winner of the RoboCup 2000 robotics competition, "Crazy Ivan", ran on Lua software.
Lua was designed and implemented by Waldemar Celes, Roberto Ierusalimschy and Luiz Henrique de Figueiredo, at the Pontifical Catholic University of Rio, Brazil. In contrast to most software developments, which sprout more bells and whistles with each new version, the Lua team actually try to cut features out if feedback from users suggests that they aren't needed. This dedication to simplicity can make hardened programmers, grown men, slack-jawed with amazement - even to bubble gently at the lips. There is a Lua mailing list where "How do I .... in Lua" questions get answered or hammered out, sometimes with spectacularly elegant solutions.
Perhaps the best way to describe Lua for Archive readers is to compare it with BBC Basic. As in Basic, in Lua all variables are taken to be global unless specifically declared to be local (but see below, where the plot thickens). However, unlike Basic, Lua can have functions returning lots of values simultaneously. So
x,y,z = position(t)
would be quite legal. Another fundamental difference is that functions are first class citizens; that is, can be stored in variables, passed as arguments or returned as results just like numbers or strings. To make the variable double have the value of the doubling function, you could write
double = function (x) return 2*x end
which could also be written in the more traditional style
function double(x) return 2*x end
There is a special value, nil, in Lua. It is the value returned by any function that has no return statement - like procedures in Basic. nil plays the role of logical FALSE, whereas any non-nil value plays the role of logical TRUE (including 0, which may trip up those used to Basic or C).
Arrays in Lua are called 'tables'. You can create an empty table called x with
x = {}
A statement
x[i] = y
will either create an index i for the table x and assign the value of y as the i-th component of x, or, if x[i] already exists, it will overwrite x[i] with the value y. The value y can be any sort of value: number, string, nil, table or function, for instance. Even the index i doesn't have to be a number; any non-nil value will do. If i is a string, say i = "tom", then x["tom"] can also be written as x.tom. You can write the statements
x = {} x[i] = p x[j] = q x[k] = r
more directly as
x = { [i] = p, [j] = q, [k] = r }
If i = "tom" then this could also be written as
x = { tom = p, [j] = q, [k] = r }
You have to be careful here. "tom = p" looks like an assignment to a variable called tom, but it's not. If indices are omitted, then the numbers 1,2, .. are used in default. For example
y = { u,v,w }
is equivalent to y = { [1] = u, [2] = v, [3] = w }.
There is a special notation for table values which are functions, when they are indexed by strings. If we had
x.tom = function (a,b,c) ........ end
then x:tom(b,c) denotes (x.tom)(x,b,c). This notation turns out to be really convenient, and it can be used to give an object-oriented style to Lua. We say that x:tom is a "method" of x. Tables of functions are particularly useful things for wimp programming because you can index a table of actions by the reason codes that Wimp_Poll returns (see the file Examples.!BasicApp.!RunImage in the RiscLua package).
Values in Lua have 'tags', which play the part of types. Tables can be given user-defined tags to distinguish the roles they are to play. Suppose we wanted to define complex numbers, say. We could write
complex_tag = newtag() -- define a new tag make_complex = function (x,y) local z={real = x, imaginary = y} settag(z,complex_tag) return z end i = make_complex(0,1)
Lua has a very powerful feature, called "tag methods", that allow you to extend the syntax. If we want to be able to write z+w and z*w for the sum and product of two complex numbers z,w then we can arrange for this by first using the commands
settagmethod(complex_tag,"add", function (z,w) return make_complex( z.real + w.real, z.imaginary + w.imaginary) end) settagmethod(complex_tag,"mul",function (z,w) return make_complex( z.real*w.real - z.imaginary*w.imaginary, z.real*w.imaginary +z.imaginary*w.real) end)
Note how the third argument to settagmethod is a function, and how we don't need to name it explicitly. Other tag methods allow you to extend virtually every aspect of the syntax to accommodate your data structures. In particular, you can use tag methods to implement various styles of object inheritance. For example, if a table x doesn't have an index i, you could use a tagmethod so that x[i], instead of returning nil, returns (x. parent)[i]. If you don't like the fact that all variables are automatically assumed global, and would prefer to have some explicit declaration, such as
global x
then you can use a tag method to implement this behaviour. In other words, tag methods give you the ability to alter the language itself. For this reason, calling Lua a language is a bit misleading. It's a language kit.
Lua comes with small libraries of predefined functions for input/output, for mathematical functions, and for text-handling. If you are creating a Lua interpreter, it is easy to add your own libraries.
The Lua interpreter compiles a Lua source program into instructions for a virtual machine and then runs it. In Lua 4.0, each virtual machine instruction is four bytes long, which is convenient for modern chips which, like the ARM, do 32-bit fetches anyway.
The rather trivial Lua code
x = { show = function (self) write("Hello\n") end } x:show()
compiles to the thirteen virtual machine instruction codes shown disassembled here:
0 00000051 CREATETABLE 1 1 00000047 PUSHSTRING 1 ; show 2 0000002E CLOSURE 0 0 3 00000016 SETMAP 0 4 00000013 SETGLOBAL 0 ; x 5 0000000C GETGLOBAL 0 ; x 6 00000050 PUSHSELF 1 ; show 7 00000002 CALL 0 0 8 00000000 END 0 0000004C GETGLOBAL 1 ; write 1 00000087 PUSHSTRING 2 ; Hello\n 2 00008002 CALL 1 0 3 00000000 END
The Lua interpreter is smart enough to distinguish when a file passed to it is a Lua program or compiled code. The function dofile can be used to execute code in a file - the file can be either a Lua program or compiled code. This plays much the same role as the LIBRARY command in Basic. There is also a function dostring analogous to Basic's EVAL.
RiscLua is an extension of Lua 4.0 to incorporate RISC OS software interrupts (corresponding to SYS in Basic). It is on this month's disc. Alternatively, you can get it from http://www.wraith.u-net.com/arc/RiscLua.arc.
Once the application !lua has been booted, running Lua programs is simply a matter of writing the program with your favourite text editor, saving the file with type "lua" (or "tasklua" for running in a task window) and double-clicking on the file's icon. Also included are a compiler and a disassembler, provided as 'stickies' (see Hints and Tips, Archive 12.10 p88), and a trivial example to show how to write wimp applications. To write a Lua program, of course, you need access to the manual, which is available as web pages on the Lua website. However, as I hope I have got across, Lua is not so much a language as a language kit for building specialized languages, and it is up to the builder to provide corresponding specialized manuals. In fact, there is some nice software for creating web page manuals automatically, out of the comments you put in your code.
I have said nothing about the Lua API - how to write C programs that use Lua or how to use C functions to extend Lua, or about the userdata type in Lua. Those who want more detail about this and other aspects of Lua can find it at Lua's website at http://www.tecgraf.puc-rio.br/lua/, also mirrored at http://csg.uwaterloo.ca/~lhf/lua/.
Source: | Archive Magazine - 14.1 |
Publication: | Archive Magazine |
Contributor: | Gavin Wraith |