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.


15.1 – The Basic Approach

A simple way to define a package is to write the package name as a prefix for each object in the package. For instance, suppose we are writing a library to manipulate complex numbers. We represent each complex number as a table, with fields r (real part) and i (imaginary part). We declare all our new operations in another table, which acts as a new package:

    complex = {}
    
    function complex.new (r, i) return {r=r, i=i} end
    
    -- defines a constant `i'
    complex.i = complex.new(0, 1)
    
    function complex.add (c1, c2)
      return complex.new(c1.r + c2.r, c1.i + c2.i)
    end
    
    function complex.sub (c1, c2)
      return complex.new(c1.r - c2.r, c1.i - c2.i)
    end
    
    function complex.mul (c1, c2)
      return complex.new(c1.r*c2.r - c1.i*c2.i,
                         c1.r*c2.i + c1.i*c2.r)
    end
    
    function complex.inv (c)
      local n = c.r^2 + c.i^2
      return complex.new(c.r/n, -c.i/n)
    end
    
    return complex
This library defines one single global name, complex. All other definitions go inside this table.

With this definition, we can use any complex operation qualifying the operation name, like this:

    c = complex.add(complex.i, complex.new(10, 20))

This use of tables for packages does not provide exactly the same functionality as provided by real packages. First, we must explicitly put the package name in every function definition. Second, a function that calls another function inside the same package must qualify the name of the called function. We can ameliorate those problems using a fixed local name for the package (P, for instance), and then assigning this local to the final name of the package. Following this guideline, we would write our previous definition like this:

    local P = {}
    complex = P           -- package name
    
    P.i = {r=0, i=1}
    function P.new (r, i) return {r=r, i=i} end
    
    function P.add (c1, c2)
      return P.new(c1.r + c2.r, c1.i + c2.i)
    end
    
       ...
Whenever a function calls another function inside the same package (or whenever it calls itself recursively), it still needs to prefix the name. At least, the connection between the two functions does not depend on the package name anymore. Moreover, there is only one place in the whole package where we write the package name.

Maybe you noticed that the last statement in the package was

    return complex
This return is not necessary, because the package is already assigned to a global variable (complex). Nevertheless, we consider a good practice that a package returns itself when it opens. The extra return costs nothing, and allows alternative ways to handle the package.