I have a personal project and a pure lua writed object module which provides metatable with methods filter
map
etc to a table , I don't want to require and setmetatable for every line local foo={}

- 23,359
- 2
- 34
- 64

- 2,456
- 2
- 28
- 41
-
1You should write a constructor for your class `Class:new()`, and set metatable for each new object in this constructor. – Egor Skriptunoff Jan 07 '22 at 16:53
2 Answers
Global Constructor
I have a personal project and a pure lua writed object module which provides metatable with methods
filter
,map
etc to a table , I don't want torequire
andsetmetatable
for every linelocal foo={}
.
You can avoid the need for require
by just ensuring that your "object module" is always loaded first, setting global variables. I consider require
to be cleaner however as it makes clear the dependencies of your files (and does not pollute the global environment).
To avoid the need for setmetatable
, you can write yourself a constructor function:
local metatable = ...
function Table(t) -- NOTE: global function
return setmetatable(t, metatable)
end
then, in another file which you ensure only runs after this file was executed:
local foo = Table{}
You might want to shorten Table
to T
if you use this very often.
Setting a metatable for all (new) tables
Do you really want this?
First of all: You probably do not want local t = {}
to set a metatable on t
. This would mess with linters like Luacheck while also making your code hard to follow for everyone familiar with Lua but unfamiliar with this hack.
Setting a metatable with __index
also interferes with the usage of tables as dictionaries / hash maps; users now need to use rawget
/ rawset
to circumvent your metatable. Consider the following snippet:
local dict = { filter = "bar" }
print(dict.filter) -- "bar", as expected
print(dict.map) -- filter function - unexpected
print(rawget(dict, "map")) -- nil, as expected
It will also harm performance of every table access. Do you really want this just for some syntactic sugar?
Furthermore, if you heavily set metamethods (such as the arithmetic metamethods) even if it doesn't really make sense, you again get unexpected behavior by allowing passing tables where numbers are expected etc. Lua's partial strictness when dealing with incompatible types is what distinguishes it from JS.
How to do it
how to automatically set default metatable to every newly created table?
This is not possible in general; the proper way to set metatables is to explicitly use constructors.
debug.setmetatable
, primitives & functions
Using debug.setmetatable
, you can set "shared"/"common" metatables for all primitive types (boolean, number, string) as well as functions. You can not set a shared metatable for objects this way however.
Hooking global/environmental variable access
This is what koyaanisqatsi's snippet does: It catches global variable access and sets the metatable on all new table global variables. This is insufficient as it forces you to use global/environmental variables, which is both bad for performance and code quality. It will in particular not work at all for local variables such as the local foo = {}
in your example. It will also not work for temporary variables in expressions (consider ({...}):filter(...)
).
Debug Hooks
The following approach would be more reliable than hooking environmental variable access:
- Set a debug hook that runs after every instruction.
- Iterate over locals & upvalues and set the metatable for each table; perhaps remember old/new locals/upvalues/tables.
- Eventually consider doing this recursively, for structures such as
{{}}
.
Obviously this would be awfully slow. It is very likely that there still exist many "edge cases" this doesn't catch (what about table creation in C, for instance?).
Forking Lua
The only proper solution would be to add such a feature - a default metatable for all tables - to the language by forking it and implementing this right in the function where Lua creates new tables. This is the only way this could be implemented adequately - that is, with adequate performance & reliability.

- 8,513
- 2
- 13
- 34
For this you can set/use the Metamethod __newindex
that triggers at defining something New.
For "every newly table" the right Place is: _G
_G = setmetatable(_G,
{__index = table,
__newindex = function(tab, key, value)
print('[__newindex]:', tab, key, value)
if type(value) == 'table' then
rawset(tab, key, setmetatable(value, getmetatable(tab)))
else
rawset(tab, key, value)
end
return
end
})
--[[ Example of use:
> a = {}
table: 0xf7ed2380 a table: 0xf7ed9738
> a:insert('Hi There!')
> print(a:concat())
Hi There!
> a[#a + 1] = {}
[__newindex]: table: 0xf7ed9738 2 table: 0xf7edbe40
]]
What will not work under LuaJIT (Lua 5.1)?
__gc will not be triggered
at alltable.insert({'I (Key [1]) am a string in a table'})
will not triggered by__newindex

- 2,585
- 2
- 8
- 15