Why does it cause a c-stack overflow? I’m new to both subjects.
local t = setmetatable({}, {
__index = function(self, i)
return self[i]
end
})
print(t[1]) -- Causes a C-Stack overflow
Why does it cause a c-stack overflow? I’m new to both subjects.
local t = setmetatable({}, {
__index = function(self, i)
return self[i]
end
})
print(t[1]) -- Causes a C-Stack overflow
I believe it gets trapped in recursive loop, because using rawset
(which doesn’t trigger metamethods) fixes it:
local t = setmetatable({}, {
__index = function(self, i)
rawset(self,i,i * 10)
return self[i]
end,
__newindex = function(self, i, v)
end
})
print(t[1]) -- prints "10"
Also I changed the code sorry I used the wrong one. Do you know why the line
return self[i]
causes the __index function to run again? That’s basically my question.
I think it’s because self[i]
is itself an index of the table, which you have a metamethod for. Try using rawget(self, i)
instead of self[i]
.
New:
local t = setmetatable({}, {
__index = function(self, i)
return rawget(self, i)
end
})
print(t[1]) -- Returns nil instead of erroring
So you mean that return self[i] triggers the __index to run again because of the self[i] and causes stack overflow?
Yes. Metamethods can trigger metamethods inside their function (Unless you use rawget
, rawset
, or rawequal
).
When you indexed it by doing t[1]
, it triggered the metamethod which tries to return self[i]
, which results in another metamethod call. This just results in cyclic metamethod calls.
You can see this if you set a cap:
local maxRun = 50
local currentRun = 0
local t = setmetatable({}, {
__index = function(self, i)
print("Running")
currentRun += 1
if currentRun >= maxRun then
return nil
end
return self[i]
end
})
print(t[1])
Which resulted in this: