Automagic Tables

lua-users home
wiki

Building on some of the techniques illustrated in FuncTables, here are some implementations of Perl-style[1] automagic tables (also called autovivication). An automagic table creates subtables on demand, as it were; i.e.:

a = AutomagicTable()

a.b.c.d = "a.b and a.b.c are automatically created"

This version was the result of several interesting interchanges between ThomasWrensch and me (RiciLake), and I cannot take credit for it (although I am happy to take the blame; I've made a couple of modifications and changed the formatting because I like spaces in parameter lists)

do

  local auto, assign



  function auto(tab, key)

    return setmetatable({}, {

            __index = auto,

            __newindex = assign,

            parent = tab,

            key = key

    })

  end



  local meta = {__index = auto}



  -- The if statement below prevents the table from being

  -- created if the value assigned is nil. This is, I think,

  -- technically correct but it might be desirable to use

  -- assignment to nil to force a table into existence.



  function assign(tab, key, val)

  -- if val ~= nil then

    local oldmt = getmetatable(tab)

    oldmt.parent[oldmt.key] = tab

    setmetatable(tab, meta)

    tab[key] = val

  -- end

  end



  function AutomagicTable()

    return setmetatable({}, meta)

  end

end

[*] There is a Lua 4 version of this as well, but it is not as tidy.


A comment made by ThomasWrensch seemed relevant, I quote it without permission so I hope he doesn't mind:

I think the technique above -- the use of an individualized metatable with additional non-metamethod keys -- is more than just a handy trick.

If you want to associate some information with a table you have three choices:

1. Put a key in the table with the information
2. Use the table as a key in another (possibly weak) table.
3. Associate it with the metatable.

The problem with the first trick is it may conflict with an existing key and/or pollute the table with inappropriate data. You pointed out some of the problems with the second approach in your message (on GarbageCollectingWeakTables) a while ago. The third requires the use of an individual metatable, but does not have the problems of the other two techniques.

-- ThomasWrensch


RecentChanges · preferences
edit · history
Last edited February 17, 2012 3:38 pm GMT (diff)