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.

13.4.5 – Read-Only Tables

It is easy to adapt the concept of proxies to implement read-only tables. All we have to do is to raise an error whenever we track any attempt to update the table. For the __index metamethod, we can use a table---the original table itself---instead of a function, as we do not need to track queries; it is simpler and quite more efficient to redirect all queries to the original table. This use, however, demands a new metatable for each read-only proxy, with __index pointing to the original table:

    function readOnly (t)
      local proxy = {}
      local mt = {       -- create metatable
        __index = t,
        __newindex = function (t,k,v)
          error("attempt to update a read-only table", 2)
      setmetatable(proxy, mt)
      return proxy
(Remember that the second argument to error, 2, directs the error message to where the update was attempted.) As an example of use, we can create a read-only table for weekdays:
    days = readOnly{"Sunday", "Monday", "Tuesday", "Wednesday",
             "Thursday", "Friday", "Saturday"}
    print(days[1])     --> Sunday
    days[2] = "Noday"
    stdin:1: attempt to update a read-only table