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 13. Metatables and Metamethods |
Both __index
and __newindex
are relevant only when
the index does not exist in the table.
The only way to catch all accesses to a table
is to keep it empty.
So, if we want to monitor all accesses to a table,
we should create a proxy for the real table.
This proxy is an empty table, with proper
__index
and __newindex
metamethods,
which track all accesses and redirect them to the original table.
Suppose that t
is the original table we want to track.
We can write something like this:
t = {} -- original table (created somewhere) -- keep a private access to original table local _t = t -- create proxy t = {} -- create metatable local mt = { __index = function (t,k) print("*access to element " .. tostring(k)) return _t[k] -- access the original table end, __newindex = function (t,k,v) print("*update of element " .. tostring(k) .. " to " .. tostring(v)) _t[k] = v -- update original table end } setmetatable(t, mt)This code tracks every access to
t
:
> t[2] = 'hello' *update of element 2 to hello > print(t[2]) *access to element 2 hello(Notice that, unfortunately, this scheme does not allow us to traverse tables. The
pairs
function will operate on the proxy,
not on the original table.)
If we want to monitor several tables, we do not need a different metatable for each one. Instead, we can somehow associate each proxy to its original table and share a common metatable for all proxies. A simple way to associate proxies to tables is to keep the original table in a proxy's field, as long as we can be sure that this field will not be used for other means. A simple way to ensure that is to create a private key that nobody else can access. Putting these ideas together results in the following code:
-- create private index local index = {} -- create metatable local mt = { __index = function (t,k) print("*access to element " .. tostring(k)) return t[index][k] -- access the original table end, __newindex = function (t,k,v) print("*update of element " .. tostring(k) .. " to " .. tostring(v)) t[index][k] = v -- update original table end } function track (t) local proxy = {} proxy[index] = t setmetatable(proxy, mt) return proxy endNow, whenever we want to monitor a table
t
,
all we have to do is t = track(t)
.
Copyright © 2003–2004 Roberto Ierusalimschy. All rights reserved. |