lua metatables question

cephalo

Deity
Joined
Jul 26, 2007
Messages
2,058
Location
Missouri, USA
I would like to make a table that stores map data in an array, but automatically converts a zero based index to a 1 based index under the hood for library functions like printing and sorting. Dealing with map data, especially when it wraps in the X direction requires alot of modulus arithmetic on the indexes and I'm used to doing things a certain way that can be complicated sometimes, and I want to simplify it for myself.

I'm learning about metatables, and it seems from the documentation that the _index metatable method is only called when a table access fails to find the index. If I try to use that to add 1 to my index, it needs to happen every time not just during failure or the wrong data will be accessed.

Anyone have any advice on how to do this? In order to do index math in the way that I'm accustomed to without a massive struggle with 1-off data errors, I'd like to create a zero based array that is also compatible with the lua library functions.
 
I only went through the tutorial once, but I do recall one method of wrapping one table inside another (maybe). The key is that the values aren't actually stored in the main table that you access, so no values exist in it, meaning _index is called for each access.

I hope that's enough to get you started at least on a good Google search. :)
 
Having had a lot of experience with Lua, my first suggestion is to just get used to 1-based arrays. It just means changing where you put your +1's and -1's. If you're an OOP junky you should also just get used to closures and metatables. Fighting city hall is counter-productive here. And after a while the Lua way will seem better.

Even so,
Code:
function zeroTable(t)

  return setmetatable({}, --blank dummy table
  {
    __index = function(self, k)
      if type(k) == "number" then
        return t[k + 1]
      end
    end,

    __newindex = function(self, k, v)
      if type(k) == "number" then
        t[k + 1] = v
      end
    end
  })
end

--I'm not in a position to test this but I'm pretty sure it should work:

local test = zeroTable{'a','b','c','d'}
print(test[0])
test[1] = 'B'
print(test[1])

This won't work with a lot of library stuff though. If you unpack it for instance, it will be empty. You could also add in a __len operator for #

edit: It seems after re-reading your post that you wanted it the other way around... Either way, it is my suggestion to just go 1-based.
 
Back
Top Bottom