Lua - Proxy Table with metatables



A proxy table can be defined as a table which is not storing actual data as it is representing to store. A proxy table is an intermediary which delegates operations to another table or another object. We can even choose to do some logic instead of storing data.

A proxy table concept becomes powerful with the use of metatables. As a metatable is to intercept operations, we can set specific metamethods for proxy table operations when any operation or interaction happens with a proxy table.

Working of Proxy Table with Metatable

  • As Step 1, create a Table as an empty table. This table will act as a proxy table for our main table.

  • As Step 2, Create a metatable for our proxy table. Metatable responsibility will be to have metamethods to define the proxy's behavior.

  • As Step 3, Implement the metamethods like following −

    • __index − handle read access. This method is called when a key is not found in proxy table. Using this method, we can do activities like−

      • Retrieve underlying value from our main table.

      • Log entries.

      • Perform access control.

      • Compute and return a dynamic value.

      • Return a default value.

    • __newindex − handle write access. This method is called when a new key is added to proxy table. Using this method, we can do activities like−

      • Store value in our main table.

      • Prevent modifications to the table, making it readonly.

      • Perform validation on the value to be added.

      • Trigger side effects if required.

    • Similarly other methods like __call, arithmetic operations like __add, logical operations like __eq or __tostring can be implemented to customized behavior of our proxy table.

  • Finally as Step 4, set the metatable using setmetatable(proxy, metatable) to associate metatable with proxy table to assign custom behavior to the proxy> table.

Example - Create a Proxy for a Read-Only table

We can create a proxy to read data from a table by implementing __index, while preventing any modification to the underlying table by use of __newindex making it effectively readonly.

main.lua

-- underlying real data
local actual_data = { name = "Julie", age = 30 }

-- an empty proxy table
local proxyTable = {}

-- metatable to prevent write access to actual_data table via proxy table.
local metatableReadOnly = {
  __index = actual_data,
  __newindex = function(table, key, value)
    error("Attempt to modify a read-only table", 2)
  end
}

-- set metatable for the proxy table
setmetatable(proxyTable, metatableReadOnly)

-- read name using proxy table, prints Julie
print(proxyTable.name) 
-- try to modify age, throws error
proxyTable.age = 31 

Output

When we run the above program, we will get the following output−

Julie
lua: main.lua:21: Attempt to modify a read-only table
stack traceback:
	[C]: in function 'error'
	main.lua:11: in metamethod 'newindex'
	main.lua:21: in main chunk
	[C]: in ?

Key Considerations

  • Proxy tables combined with metatables is a powerful mechanism to control and customize unlying table behavior.

  • __index and __newindex are two fundamental metamethods to intercept read/write access to the table.

  • Using proxy tables we can achieve read-only access, lazy loading to load data when required, perform validation, delegation and tracing of events.

Advertisements