5

I'd like to have a write-once table in Lua (specifically LuaJIT 2.0.3), so that:

local tbl = write_once_tbl()
tbl["a"] = 'foo'
tbl["b"] = 'bar'
tbl["a"] = 'baz'  -- asserts false

Ideally, this would otherwise function like a regular table (pairs() and ipairs() work).

__newindex is basically the opposite of what I'd want for implementing this easily, and I am unaware of any techniques for making a proxy table pattern work with pairs() and ipairs().

MikeMx7f
  • 927
  • 6
  • 13

1 Answers1

6

You need to use a proxy table, that is, an empty table that catches all access to the actual table:

function write_once_tbl()
    local T={}
    return setmetatable({},{
        __index=T,
        __newindex=
            function (t,k,v)
                if T[k]==nil then
                    T[k]=v
                else
                    error("table is write-once")
                end
            end,
        __pairs=  function (t) return  pairs(T) end,
        __ipairs= function (t) return ipairs(T) end,
        })
end

Note that __pairs and __ipairs only work from Lua 5.2 onwards.

lhf
  • 70,581
  • 9
  • 108
  • 149
  • I know of proxy tables, but they do *not* work with pairs() or ipairs(). I just tried your code snippet and verified that pairs() and ipairs() do not work with it. – MikeMx7f Nov 13 '17 at 23:47
  • @MikeMx7f, they do in Lua 5.2 and 5.3. – lhf Nov 14 '17 at 00:09
  • I tested your code snippet here: https://www.lua.org/cgi-bin/demo which is using Lua 5.3. – MikeMx7f Nov 15 '17 at 19:47
  • @MikeMx7f, you need to set `__pairs` and `__ipairs` metamethods. – lhf Nov 15 '17 at 19:49
  • Thanks. Can you edit that into the answer so I can accept it (since the question specifies pairs() and ipairs() works)? Cheers. – MikeMx7f Nov 15 '17 at 19:59