Lua Protected Metatables
A protected metatable hides the real metatable from getmetatable. getmetatable returns the protection value instead.
getmetatable returns the protection value
The metatable carries __metatable set to locked. getmetatable returns locked, not the real metatable.
local t = {}
local mt = {__metatable = "locked"}
setmetatable(t, mt)
print(getmetatable(t))rawget skips __index
__index supplies x from a fallback table. rawget looks only in the table itself, so it finds nothing.
local fallback = {x = 99}
local t = setmetatable({}, {__index = fallback})
print(t.x)
print(rawget(t, "x") == nil)rawset skips __newindex
__newindex logs every normal write instead of storing it. A raw write stores the value directly.
local log = {}
local mt = {__newindex = function(tbl, k, v) log[#log + 1] = k end}
local t = setmetatable({}, mt)
t.a = 1
rawset(t, "b", 2)
print(rawget(t, "a") == nil)
print(rawget(t, "b"))
print(#log)Example
local fallback = {score = 50}
local t = {}
local mt = {}
mt.__metatable = "locked"
mt.__index = fallback
mt.__newindex = function() end
mt.__pairs = function()
local done = false
return function()
if not done then
done = true
return "custom", 7
end
end
end
setmetatable(t, mt)
print(getmetatable(t))
print(t.score)
rawset(t, "score", 80)
print(rawget(t, "score"))
for k, v in pairs(t) do
print(k, v)
end
print(next(t))Key points
- __metatable: __metatable is a field in a metatable that sets the protection value.
- getmetatable: getmetatable on a protected table returns the protection value, not the real metatable.
- setmetatable: replacing the metatable of a protected table fails.
- rawget: rawget reads a table field without calling any metamethod.
- rawset: rawset writes a table field without calling any metamethod.
- Bypass: raw functions bypass metamethods, including __index and __pairs.
In this example, getmetatable returns locked for the protected table. Reading score uses __index and gives 50, while rawset stores 80 directly. The pairs walk yields the custom key, but next walks the raw table and gives score.
Note
protection only changes what getmetatable returns, so raw access to the table still works.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
getmetatable returns "locked" for a table. What can you conclude?