This code has been tested with Lua 5.1.5, Lua 5.2.3, Lua 5.3.5, and LuaJIT 2.0.5. To build, simply `make` or for LuaJIT: `make LUA=luajit` (you can also optionally specify `LUA_INC=<path to the directory containing lua.h and lauxlib.h>` or `LUA_BIN=<path to the directory containing the lua binary>`).
This library adds support for two new metamethods: `__new` and `__missing`. `__new` is called when an instance is created. It takes as arguments the immutable class and all arguments the user passed in, and whatever values it returns are used to create the instance. This is pretty handy for default or derived values.
```lua
local Foo = immutable({"x","y","xy"}, {
__new = function(cls, x, y)
y = y or 3
return x, y, x*y
end
})
assert(Foo(2).xy == 6)
```
`__missing` is similar to `__index`, except that it only gets called when accessing a key that is neither one of the immutable class's instance keys, nor one of the keys in the class table.
```lua
local Foo = immutable({"x","y"}, {
classvar = 23,
__missing = function(self, key)
return "MISSING"
end
})
local f = Foo(1, nil)
assert(f.x == 1 and f.y == nil and f.classvar == 23 and f.asdf == "MISSING")
This library is pretty dang fast, but it's still slower than native Lua tables. Based on my local testing, immutable tables add a couple nanoseconds to table operations in the worst case scenario. In LuaJIT, there is a bigger performance discrepancy because regular tables are more heavily optimized in LuaJIT. Your mileage may vary, but I'd say that immutable tables will probably never be a performance bottleneck for your program, especially if you use them in place of code that already used a constructor function and metatables. In some cases, immutable tables may also help reduce your program's memory footprint (if your program has many duplicate objects in memory) and may even improve speed (e.g. if your program uses a lot of deep equality checks). Don't trust this paragraph though! If in doubt, profile your code!