Metatables question

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:

1 Like