Stack Overflow on Lua metatable

Viewed 60

I used to have a construct that worked with luajit:

mytbl = setmetatable({1}, {__index = function(tbl,idx) return tbl[idx - 1] + 1 end})

Now with plain Lua 5.4 this gives me a stack overflow:

> mytbl[1000]
stdin:1: C stack overflow
stack traceback:
    stdin:1: in metamethod 'index'
    ....

The goal is to have a table where the default is to return the index itself:

mytbl[10] 

should return 10. But when I say

mytbl[3] = 5

the value of

mytbl[10]

should be 12 (the values from 1 now yield 1,2,5,6,7,8,9,10,11,12,...)

Is there a way to get this in Lua 5.4 without the stack overflow? Or should I create another function for it?

2 Answers

You are accessing the table within the __index. That causes another __index to be called and so on.

Use rawget when you want to access the tbl itself.

If you want to get a custom logic that does not rely on existence of elements, write your function in a way that allows for trailing recursion or write it iteratively without any recursion at all:

__index=function(tbl, idx)
  local acc = 0
  for i=idx-1, 1, -1 do
    local th = rawget(tbl, i)
    if th then
      return acc + th + 1
    else
      acc = acc + 1
    end
  end
  return acc
end

This is what I came up with now:

__index=function(tbl, idx)
    local max = 0
    for k, v in next, tbl do
      if k <= idx then max = v - k end
    end
    return idx + max
  end 

I only have very few entries in tbl so this should be reasonable fast for my purposes.

My test:

mytbl[5] = 9
for i = 1, 10 do
  print(mytbl[i])
end

outputs

1
2
3
4
9
10
11
12
13
14
Related