Metatable not printing out anyhting

Creature.__index = function(tab , index) return rawget(tab , index) or rawget(Creature , index) or warn("indexed " .. index .. ", is " .. tostring(rawget(tab , index)) .. ". line #" .. tostring(debug.info(2, "l")) , tab) end
Creature.__newindex = function(Table , Key , Value) 
	print(Key)
	if Key == "Energy" or Key == "Health" then
		rawset(Table , Key , math.clamp(math.floor(Value + 0.5) , 0 , math.huge)) 
		print("HEALTH OR ENERGY CHANGED")
	elseif Key == "StatusEffect" and Table.StatusEffect == "Healthy" then
		print(Table)
		rawset(Table , Key , Value)
	else
		rawset(Table , Key , Value)
	end
end

I was working on a class for my game, but then i realised that metatables were not printing out any thing, despite the metamethods definitely being called at some point, as i did change some value.
That said the index metamethod shown here works for some reason.

If you are trying to print out the metatable then do

print(getmetatable(Table))

Other than that I can’t say I understand what you are saying. What exactly are you looking for or want?

The functions that are displayed should print out things when the corresponding metamethod triggers, but nothing prints.

Oh! I see what you mean now. I’ve run into this problem before and was just as confused. It turns out that the __newindex metamethod only fires when a new property is indexed. In other words, the property that you are trying to change cannot be directly in the table or metatable. It’s dumb that we don’t have an event to detect when a property changes, but it is what it is. In order to circumvent this, you have to use a proxy table.

You can check out the resource I’ve linked below for more info. It’s what initially helped me.
https://www.lua.org/pil/13.4.4.html

Basically you need to create a proxy table that you store the variables you want __newindex to fire on.
An example might be this:

local example = setmetatable({result = {}}, {
	__tostring = function()
		return "Example" -- the name
	end,
	__index = function(proxy, key)
		local result = rawget(proxy,"result")
		
		if result[key] ~= nil then
			print(string.format("%q was accessed", key))
		else
			error(string.format("%s is not a valid member of %s %q", key, tostring(proxy), tostring(proxy)))
		end
		
		return result[key]
	end,
	__newindex = function(proxy, key, value)
		local result = rawget(proxy,"result")
		
		if result[key] ~= nil then -- shows what action is being done
			if value == nil then
				print(string.format("%q was deleted", key))
			elseif result[key] ~= value then
				print(string.format("%q was changed", key))
			end
		else
			print(string.format("%q was set", key))
		end
		
		result[key] = value -- set the value
	end
})

print(example)
example.test = true -- "test" was set
example.test = false -- "test" was changed
print(example.test) -- "test was accessed
-- false
example.test = nil; -- "test" was deleted
print(example.test) -- Error: test is not a valid member of Example "Example"

Note: Setting this up with the table you use being the proxy means that Roblox’s type-inference engine won’t be able to tell what variables are being stored in the table. However, you can fool it using type checking.

1 Like

I don’t undersand what you’re doing differently, you’re still using the newindex metamethod, and the index metamethod does nothing but error when you set something that isn’t in the proxxy table. why does this work differently?

Also would this error if something is on the table but not on the proxy table, and then you index that?

Ah i see now, so the proxy table is actually kept empty so index and newindex can always trigger, and the metamethods return references to the real table, clever.

Just a bit confused by your response here. Are you having any additional troubles or were you just puzzling how it worked? If so, then you can just dm me.

I was having issues but i figured it out, thanks :pray:t2: