This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.
The fourth edition targets Lua 5.3 and is available at Amazon and other bookstores.
By buying the book, you also help to support the Lua project.
Programming in Lua | ||
Part II. Tables and Objects Chapter 15. Packages |
As I said earlier, the use of tables to implement packages allows us to use the whole power of Lua to manipulate them. There are unlimited possibilities. Here I will give only a few suggestions.
We do not need to define all public items of a package together.
For instance, we can add a new item to our complex
package
in a separate chunk:
function complex.div (c1, c2) return complex.mul(c1, complex.inv(c2)) end(But notice that the private part is restricted to one file, which I think is a good thing.) Conversely, we can define more than one package in the same file. All we have to do is to enclose each one inside a do block, so that its local variables are restricted to that block.
Outside the package, if we are going to use some operations often, we can give them local names:
local add, i = complex.add, complex.i c1 = add(complex.new(10, 20), i)Or else, if we do not want to write the package name over and over, we can give a shorter local name to the package itself:
local C = complex c1 = C.add(C.new(10, 20), C.i)
It is easy to write a function that unpacks a package, putting all its names into the global namespace:
function openpackage (ns) for n,v in pairs(ns) do _G[n] = v end end openpackage(complex) c1 = mul(new(10, 20), i)If you are afraid of name clashes when opening a package, you can check the name before the assignment:
function openpackage (ns) for n,v in pairs(ns) do if _G[n] ~= nil then error("name clash: " .. n .. " is already defined") end _G[n] = v end end
Because packages themselves are tables, we can even nest packages; that is, we can create a package inside another one. However, this facility is seldom necessary.
Another interesting facility is autoload,
which only loads a function if the function is actually used by the program.
When we load an autoload package,
it creates an empty table to represent the package and
sets the __index
metamethod of the table to do the autoload.
Then, when we call any function that is not yet loaded,
the __index
metamethod is invoked to load it.
Subsequent calls find the function already loaded;
therefore, they do not activate the metamethod.
A simple way to implement autoload can be as follows. Each function is defined in an auxiliary file. (There can be more than one function in each file.) Each of these files defines its functions in a standard way, for instance like here:
function pack1.foo () ... end function pack1.goo () ... endHowever, the file does not create the package, because the package already exists when the function is loaded.
In the main package we define an auxiliary table that describes where we can find each function:
local location = { foo = "/usr/local/lua/lib/pack1_1.lua", goo = "/usr/local/lua/lib/pack1_1.lua", foo1 = "/usr/local/lua/lib/pack1_2.lua", goo1 = "/usr/local/lua/lib/pack1_3.lua", }Then we create the package and define its metamethod:
pack1 = {} setmetatable(pack1, {__index = function (t, funcname) local file = location[funcname] if not file then error("package pack1 does not define " .. funcname) end assert(loadfile(file))() -- load and run definition return t[funcname] -- return the function end}) return pack1After loading this package, the first time the program executes
pack1.foo()
it
will invoke that __index
metamethod,
which is quite simple.
It checks that the function has a corresponding file
and loads that file.
The only subtlety is that it must not only load the file,
but also return the function as the result
of the access.
Because the entire system is written in Lua,
it is easy to change its behavior.
For instance, the functions may be defined in C,
with the metamethod using loadlib
to load them.
Or we can set a metamethod in the global table to autoload
entire packages.
The possibilities are endless.
Copyright © 2003–2004 Roberto Ierusalimschy. All rights reserved. |