Cours programming with Lua, tutoriel & guide de travaux pratiques en pdf.
Data Description
Lua was born from a data-description language, called SOL [8], a language some-what similar to XML in intent. Lua inherited from SOL the support for data description, but integrated that support into its procedural semantics.
SOL was somewhat inspired by BibTeX, a tool for creating and formating lists of bibliographic references [9]. A main di erence between SOL and BibTeX was that SOL had the ability to name and nest declarations. Figure 1 shows a typical fragment of SOL code, slightly adapted to meet the current syntax of Lua. SOL acted like an XML DOM reader, reading the data le and building an internal tree representing that data; an application then could use an API to traverse that tree.
Lua mostly kept the original SOL syntax, with small changes. The semantics, however, was very di erent. In Lua, the code in Figure 1 is an imperative pro-gram. The syntax {first = « Daniel », …} is a constructor: it builds a table,
dan = name{first = « Daniel », last = « Friedman »}
mitch = name{last = « Wand »,
first = « Mitchell »,
middle = « P. »}
chris = name{first = « Christopher », last = « Haynes »}
book{« essentials »,
author = {dan, mitch, chris},
title = « Essentials of Programming Languages »,
edition = 2,
year = 2001,
publisher = « The MIT Press »
}
or associative array, with the given keys and values. The syntax name{…} is sugar for name({…}), that is, it builds a table and calls function name with that table as the sole argument. The syntax {dan,mitch,chris} again builds a table, but this time with implicit integer keys 1, 2, and 3, therefore representing a list. A program loading such a le should previously de ne functions name and book with appropriate behavior. For instance, function book could add the table to some internal list for later treatment.
Several applications use Lua for data description. Games frequently use Lua to describe characters and scenes. HiQLab, a tool for simulating high frequency resonators, uses Lua to describe nite-element meshes [10]. GUPPY uses Lua to describe sequence annotation data from genome databases [11]. Some descrip-tions comprise thousands of elements running for a few million lines of code. The user sees these les as data les, but Lua sees them as regular code. These huge \programs » pose a heavy load on the Lua precompiler. To handle such les e ciently, and also for simplicity, Lua uses a one-pass compiler with no interme-diate representations. As we will see in the next section, this requirement puts a burden on other aspects of the implementation.
Functional Programming
Lua o ers rst-class functions with lexical scoping. For instance, the following code is valid Lua code:
(function (a,b) print(a+b) end)(10, 20)
It creates an anonymous function that prints the sum of its two parameters and applies that function to arguments 10 and 20.
All functions in Lua are anonymous dynamic values, created at run time. Lua o ers a quite conventional syntax for creating functions, like in the following
de nition of a factorial function:
function fact (n)
if n <= 1 then return 1
else return n * fact(n – 1)
end
end
However, this syntax is simply sugar for an assignment:
fact = function (n)
…
end
This is quite similar to a define in Scheme [12].
Lua does not o er a letrec primitive. Instead, it relies on assignment to close a recursive reference. For instance, a strict recursive xed-point operator can be de ned like this:
local Y
Y = function (f)
return function (x)
return f(Y(f))(x)
end
end
Or, using some syntactic sugar, like this:
local function Y (f)
return function (x)
return f(Y(f))(x)
end
end
This second fragment expands to the rst one. In both cases, the Y in the function body is bounded to the previously declared local variable.
Of course, we can also de ne a strict non-recursive xed-point combinator in
Lua:
Y = function (le)
local a = function (f)
return le(function (x) return f(f)(x) end)
end
return a(a)
end
Despite being a procedural language, Lua frequently uses function values. Several functions in the standard Lua library are higher-order. For instance,
the sort function accepts a comparison function as argument. In its pattern-matching functions, text substitution accepts a replacement function that re-ceives the original text matching the pattern and returns its replacement. The standard library also o ers some traversal functions, which receive a function to be applied to every element of a collection.
Most programming techniques for strict functional programming also work without modi cations in Lua. As an example, LuaSocket, the standard library for network connection in Lua, uses functions to allow easy composition of di erent functionalities when reading from and writing to sockets [13].
Lua also features proper tail calls. Again, although this is a feature from the functional world, it has several interesting uses in procedural programs. For instance, it is used in a standard technique for implementing state machines [4]. In these implementations, each state is represented by a function, and tail calls transfer the program from one state to another.
Closures
The standard technique for implementing strict rst-class functions with lexical scoping is with the use of closures. Most implementations of closures neglect as-signment. Pure functional languages do not have assignment. In ML assignable cells have no names, so the problem of assignment to lexical-scoped variables does not arise. Since Rabbit [14], most Scheme compilers do assignment con-versions, that is, they implement assignable variables as ML cells on the correct ground that they are not used often.
None of those implementations t Lua, a procedural language where assign-ment is the norm. Moreover, as we already mentioned, Lua has an added require-ment that its compiler must be fast, to handle huge data-description \programs », and small. So, Lua uses a simple one-pass compiler with no intermediate repre-sentations which cannot perform even escape analysis.