Stack Overflow on Lua metatable - lua

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?

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

How to implement combinations tail-recursively?

I'm teaching myself Lua by reading Ierusalimschy's Programming in Lua (4th edition), and doing the exercises. Exercise 6.5 is
Write a function that takes an array and prints all combinations of the elements in the array.
After this succinct statement the book gives a hint that makes it clear that what one is expected to do is to write a function that prints all the C(n, m) combinations of m elements from an array of n elements.
I implemented the combinations function shown below:
function combinations (array, m)
local append = function (array, item)
local copy = {table.unpack(array)}
copy[#copy + 1] = item
return copy
end
local _combinations
_combinations = function (array, m, prefix)
local n = #array
if n < m then
return
elseif m == 0 then
print(table.unpack(prefix))
return
else
local deleted = {table.unpack(array, 2, #array)}
_combinations(deleted, m - 1, append(prefix, array[1]))
_combinations(deleted, m, prefix)
end
end
_combinations(array, m, {})
end
It works OK, but it is not tail-recursive.
Can someone show me a tail-recursive function that does the same thing as combinations above does?
(For what it's worth, I am using Lua 5.3.)
NB: I realize that the exercise does not require that the function be tail-recursive. This is a requirement I have added myself, out of curiosity.
EDIT: I simplified the function slightly, but removing a couple of nested functions that were not adding much.
There is a third option, one that doesn't have a snake eating it's tail. Although recursion with tail-calls don't lead to stack overflow, I avoid doing so out of personal preference. I use a while loop and a stack that holds the information for each iteration. Within the loop you pop the next task from the stack, do the work, then push next task onto the stack. I feel it looks cleaner and it's easier to visualize the nesting.
Here is how I would translate your code into the way I would write it:
function combinations(sequence, item)
local function append(array, item)
local copy = {table.unpack(array)}
copy[#copy + 1] = item
return copy
end
local stack = {}
local node = { sequence, item, {} }
while true do
local seq = node[ 1 ]
local itm = node[ 2 ]
local pre = node[ 3 ]
local n = #seq
if itm == 0 then
print(table.unpack(pre))
elseif n < itm then
-- do nothing
else
local reserve = {table.unpack(seq, 2, #seq)}
table.insert(stack, { reserve, itm, pre })
table.insert(stack, { reserve, itm-1, append(pre, seq[ 1 ]) })
end
if #stack > 0 then
node = stack[ #stack ] -- LIFO
stack[ #stack ] = nil
else
break
end
end
end
You can use this while-loop stack/node technique for just about any recursive method. Here is an example where it's applied to printing deeply nested tables: https://stackoverflow.com/a/42062321/5113346
My version, using your input example gives the same output:
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5.
Forgive me if it doesn't work with other passed params because I didn't try to solve the answer to the exercise but rather just rewrite the code in your original post.
OK, I think I found one way to do this:
function combinations (array, m)
local dropfirst = function (array)
return {table.unpack(array, 2, #array)}
end
local append = function (array, item)
local copy = {table.unpack(array)}
copy[#copy + 1] = item
return copy
end
local _combinations
_combinations = function (sequence, m, prefix, queue)
local n = #sequence
local newqueue
if n >= m then
if m == 0 then
print(table.unpack(prefix))
else
local deleted = dropfirst(sequence)
if n > m then
newqueue = append(queue, {deleted, m, prefix})
else
newqueue = queue
end
return _combinations(deleted, m - 1,
append(prefix, sequence[1]),
newqueue)
end
end
if #queue > 0 then
newqueue = dropfirst(queue)
local newargs = append(queue[1], newqueue)
return _combinations(table.unpack(newargs))
end
end
_combinations(sequence, m, {}, {})
end
This version is, I think, tail-recursive. Unfortunately, it does not print out the results in as nice an order as did my original non-tail-recursive version (not to mention the added complexity of the code), but one can't have everything!
EDIT: Well, no, one can have everything! The version below is tail-recursive, and prints its results in the same order as does the original non-tail-recursive version:
function combinations (sequence, m, prefix, stack)
prefix, stack = prefix or {}, stack or {}
local n = #sequence
if n < m then return end
local newargs, newstack
if m == 0 then
print(table.unpack(prefix))
if #stack == 0 then return end
newstack = droplast(stack)
newargs = append(stack[#stack], newstack)
else
local deleted = dropfirst(sequence)
if n > m then
newstack = append(stack, {deleted, m, prefix})
else
newstack = stack
end
local newprefix = append(prefix, sequence[1])
newargs = {deleted, m - 1, newprefix, newstack}
end
return combinations(table.unpack(newargs)) -- tail call
end
It uses the following auxiliary functions:
function append (sequence, item)
local copy = {table.unpack(sequence)}
copy[#copy + 1] = item
return copy
end
function dropfirst (sequence)
return {table.unpack(sequence, 2, #sequence)}
end
function droplast (sequence)
return {table.unpack(sequence, 1, #sequence - 1)}
end
Example:
> combinations({1, 2, 3, 4, 5}, 3)
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
Ironically, this version achieves tail-recursion by implementing its own stack, so I am not sure it is ultimately any better than the non-tail-recursive version... Then again, I guess the function's stack actually lives in the heap (right?), because Lua's tables are passed around by reference (right?), so maybe this is an improvement, after all. (Please correct me if I'm wrong!)

Lua #Table returning 0, despite Table containing 3 elements (tables)? [duplicate]

Sounds like a "let me google it for you" question, but somehow I can't find an answer. The Lua # operator only counts entries with integer keys, and so does table.getn:
tbl = {}
tbl["test"] = 47
tbl[1] = 48
print(#tbl, table.getn(tbl)) -- prints "1 1"
count = 0
for _ in pairs(tbl) do count = count + 1 end
print(count) -- prints "2"
How do I get the number of all entries without counting them?
You already have the solution in the question -- the only way is to iterate the whole table with pairs(..).
function tablelength(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
Also, notice that the "#" operator's definition is a bit more complicated than that. Let me illustrate that by taking this table:
t = {1,2,3}
t[5] = 1
t[9] = 1
According to the manual, any of 3, 5 and 9 are valid results for #t. The only sane way to use it is with arrays of one contiguous part without nil values.
You can set up a meta-table to track the number of entries, this may be faster than iteration if this information is a needed frequently.
The easiest way that I know of to get the number of entries in a table is with '#'. #tableName gets the number of entries as long as they are numbered:
tbl={
[1]
[2]
[3]
[4]
[5]
}
print(#tbl)--prints the highest number in the table: 5
Sadly, if they are not numbered, it won't work.
There's one way, but it might be disappointing: use an additional variable (or one of the table's field) for storing the count, and increase it every time you make an insertion.
count = 0
tbl = {}
tbl["test"] = 47
count = count + 1
tbl[1] = 48
count = count + 1
print(count) -- prints "2"
There's no other way, the # operator will only work on array-like tables with consecutive keys.
function GetTableLng(tbl)
local getN = 0
for n in pairs(tbl) do
getN = getN + 1
end
return getN
end
You're right. There are no other way to get length of table
You could use penlight library. This has a function size which gives the actual size of the table.
It has implemented many of the function that we may need while programming and missing in Lua.
Here is the sample for using it.
> tablex = require "pl.tablex"
> a = {}
> a[2] = 2
> a[3] = 3
> a['blah'] = 24
> #a
0
> tablex.size(a)
3
local function CountedTable(x)
assert(type(x) == 'table', 'bad parameter #1: must be table')
local new_t = {}
local mt = {}
-- `all` will represent the number of both
local all = 0
for k, v in pairs(x) do
all = all + 1
end
mt.__newindex = function(t, k, v)
if v == nil then
if rawget(x, k) ~= nil then
all = all - 1
end
else
if rawget(x, k) == nil then
all = all + 1
end
end
rawset(x, k, v)
end
mt.__index = function(t, k)
if k == 'totalCount' then return all
else return rawget(x, k) end
end
return setmetatable(new_t, mt)
end
local bar = CountedTable { x = 23, y = 43, z = 334, [true] = true }
assert(bar.totalCount == 4)
assert(bar.x == 23)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = nil
assert(bar.totalCount == 3)
bar.x = 24
bar.x = 25
assert(bar.x == 25)
assert(bar.totalCount == 4)
I stumbled upon this thread and want to post another option. I'm using Luad generated from a block controller, but it essentially works by checking values in the table, then incrementing which value is being checked by 1. Eventually, the table will run out, and the value at that index will be Nil.
So subtract 1 from the index that returned a nil, and that's the size of the table.
I have a global Variable for TableSize that is set to the result of this count.
function Check_Table_Size()
local Count = 1
local CurrentVal = (CueNames[tonumber(Count)])
local repeating = true
print(Count)
while repeating == true do
if CurrentVal ~= nil then
Count = Count + 1
CurrentVal = CueNames[tonumber(Count)]
else
repeating = false
TableSize = Count - 1
end
end
print(TableSize)
end
seems when the elements of the table is added by insert method, getn will return correctly. Otherwise, we have to count all elements
mytable = {}
element1 = {version = 1.1}
element2 = {version = 1.2}
table.insert(mytable, element1)
table.insert(mytable, element2)
print(table.getn(mytable))
It will print 2 correctly

Explain why unpack() returns different results in Lua

The following script finds prime numbers in a range from 1 to 13.
When I explicitly iterate over the table that contains the results I can see that the script works as expected. However, if I use unpack() function on the table only the first 3 numbers get printed out.
From docs: unpack is "a special function with multiple returns. It receives an array and returns as results all elements from the array, starting from index 1".
Why is it not working in the script below?
t = {}
for i=1, 13 do t[i] = i end
primes = {}
for idx, n in ipairs(t) do
local isprime = true
for i=2, n-1 do
if n%i == 0 then
isprime = false
break
end
end
if isprime then
primes[idx] = n
end
end
print('loop printing:')
for i in pairs(primes) do
print(i)
end
print('unpack:')
print(unpack(primes))
Running
$ lua5.3 primes.lua
loop printing:
1
2
3
5
7
13
11
unpack:
1 2 3
Change
primes[idx] = n
to
primes[#primes+1] = n
The reason is that idx is not sequential as not every number is a prime.

how are the index applied in upvalue + lua

I'm trying to understand how are index applied in upvalue but unable to get so as led me to ask this question over here.
function newCounter ()
local t = 10
local n = 0
local k = 0
return function ()
l = t
k = n
n = n + 1
return n
end
end
counter = newCounter()
counter()
counter()
print("<==============>")
local i = 1
repeat
name, val = debug.getupvalue(counter, i)
if name then
print ("index", i, name, "=", val)
if (name == "n") then
debug.setupvalue(counter,2,10)
end
i = i + 1
end -- if
until not name
When I run this I get following o/p
index 1 _ENV = table: 0x7f8203c03ea0
index 2 t = 10
index 3 k = 1
index 4 n = 2
Note : I was assuming the o/p to be (based on the order in which they are initialise)
index 1 t = 10
index 2 k = 1
index 3 n = 2
index 4 _ENV = table: 0x7f8203c03ea0
Can any provide me an info as to what is the logical way to find the correct index associate with a given upvalue.
Every chunk in Lua starts with _ENV as its first upvalue.

lua - table maintenance (particle system related)

The update() function below gets called on every frame of a game. If the Drop particle has y value greater than 160 I want to remove it from the table. The problem is that I get "attempt to compare number with nil" errors, on the line notated below:
local particles = {};
function update()
local num = math.random(1,10);
if(num < 4) then
local drop = Drop.new()
table.insert ( particles, drop );
end
for i,val in ipairs(particles) do
if(val.y > 160) then --ERROR attempt to compare number with nil
val:removeSelf(); --removeSelf() is Corona function that removes the display object from the screen
val = nil;
end
end
end
What am I doing wrong? Obviously val is nil, but I don't understand why the table iteration would find val in the first place since I set it to nil when it's y value gets larger than 160.
Thanks for the answers, they were all helpful. Here is what ended up working for me. The table.remove call is necessary to keep the loop running properly.
for i = #particles, 1, -1 do
if particles[i].y > 160 then
local child = table.remove(particles, i)
if child ~= nil then
display.remove(child)
child = nil
end
end
end
You're looking in the wrong place, the problem isn't that val is nil, it's val.y that's nil. See this example:
> x=nil
> if x.y > 10 then print("test") end
stdin:1: attempt to index global 'x' (a nil value)
stack traceback:
stdin:1: in main chunk
[C]: ?
> x={y=nil}
> if x.y > 10 then print("test") end
stdin:1: attempt to compare number with nil
stack traceback:
stdin:1: in main chunk
[C]: ?
Also, when you set val to nil, that may not be doing anything (I believe val is a copy):
> t={"a", "b", "c", "d"}
> for i,val in ipairs(t) do print(i, val) end
1 a
2 b
3 c
4 d
> for i,val in ipairs(t) do if i==3 then print("delete", val); val=nil end end
delete c
> for i,val in ipairs(t) do print(i, val) end
1 a
2 b
3 c
4 d
Edit: to delete an element from a table, you want table.remove:
> t[3]=nil
> for i,val in ipairs(t) do print(i, val) end
1 a
2 b
> t[3]="c"
> for i,val in ipairs(t) do print(i, val) end
1 a
2 b
3 c
4 d
> for i,val in ipairs(t) do if i==3 then print("delete", val); table.remove(t, i) end end
delete c
> for i,val in ipairs(t) do print(i, val) end
1 a
2 b
3 d
JeffK's solution should work, but I think the reason it will work is not because of the fact that he's traversing the list backwards, but because he is setting particles[i] = nil instead of val = nil. If you run val = nil you're only setting the local copy of val to nil, not the entry in the table.
Try this:
for i,val in ipairs(particles) do
if(val.y > 160) then
particles[i]:removeSelf()
particles[i] = nil;
end
end
I don't think you are allowed to modify the contents of a table while ipairs is iterating through it. I vaguely remember reading that my hardcopy of the Lua 5.1 Reference Manual, but I can't seem to locate it now. When you set val to nil, it removes an element from the particles table.
You might try processing the table in reverse, since your function is doing a full sweep of the particles table, conditionally removing some items:
for x = #particles, 1, -1 do
if particles[x].y > 160 then
particles[x]:removeSelf()
particles[x] = nil
end
end

Resources