Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

Is there a way to see if a new value was added to a table?

I was wondering if there is a metamethod or some other thing that will allow me to see if a new value was added to a table?

--[[Purpose:I'm making a script that is finding npcs with the value "Shop"
and making them into a shop]]--

NPCs={}--Table where the npc's will be stored

function FindNpc()--Will Search Workspace for a humanoid if it finds it then it search for the value "Shop" then insert the NPC to the Table
	for Index,Objects in pairs(game.Workspace:GetChildren()) do
		local FoundHumanoid = Objects:FindFirstChild("Humanoid")
			if FoundHumanoid then
				local FoundShopValue = FoundHumanoid:FindFirstChild("Value")
				if FoundShopValue then
					if FoundShopValue.Value == "Shop" then
						table.insert(NPCs,FoundHumanoid.Parent)
					end
				end
			end
	end
end
FindNpc()
--To be Finished

Edited:

--[[Purpose:I'm making a script that is finding npcs with the value "Shop"
and making them into a shop]]--

NPCs={}--Table where the npc's will be stored
Metatable = {
    __newindex = function(self,index,value)
        print(value)
    end
}

setmetatable(NPCs,Metatable)

function FindNpc()--Will Search Workspace for a humanoid if it finds it then it search for the value "Shop" then insert the NPC to the Table
    for Index,Objects in pairs(game.Workspace:GetChildren()) do
        local FoundHumanoid = Objects:FindFirstChild("Humanoid")
            if FoundHumanoid then
                local FoundShopValue = FoundHumanoid:FindFirstChild("Value")
                if FoundShopValue then
                    if FoundShopValue.Value == "Shop" then
                        table.insert(NPCs,FoundHumanoid.Parent)
                        NPCs.x = "a"-- Y U NO print the value
                    end
                end
            end
    end
end
FindNpc()
--print(NPCs[1])
--To be Finished

If there is a way to see if a value was added to a table if so what is it?

2 answers

✓ Accepted answer

The __newindex metamethod should do the trick. It triggers when a new index is added to a table without the use of the function rawset (this suggests that table.insert will not trigger __newindex).

Here's an example that prints out the index and the value when it is set...

local t = { }
setmetatable(t, {
	__newindex = function(self, index, value)
		print(index, "=", value)
	end
})
t.x = "a" --> x = "a"
table.insert(t, "test") --> no output, uses table.insert
t[2] = 2 --> 2 = 2

4 comments

0

Sorry to ask this but I just learned how to use metatables and I was wondering why did you put "t.x = "a" if there is no x in the table t?

1

That isn't a metatable question as much as it is a table question. A singular period symbol is what we call "syntactical sugar" for square brackets (so t.x = a is the same as t["x"] = a). By accessing this index which has nothing yet in t and then setting it equal to some value, I trigger the __newindex metamethod.

0

Thanks, and I put the metatable part that you showed me and it won't print.Why?

1

__newindex has two underscores, not one. All metamethods use two underscores.

Sukinahito's answer is a good, direct answer to the question. (I believe Lua 5.3 even fixes the problem that table.insert ignores metatables -- though since ROBLOX is on 5.1, that's a long, long ways away (you can also fix it yourself))

However, that is not the best approach to take to solve this problem.


There is a concept (that comes largely from Object Oriented Programming) called information hiding in computer science. This means separating the way you use something with the way that it works.

In this case, it would mean that when you're trying to make new NPCs (or remove them, get them, etc) you don't actually use the NPCs table; you instead use a few functions (which are the only way to get to the NPCs table)

This means you can do lots of extra stuff, like responding to a new element, without having a complicated API. It also means you won't confuse the user since there will be an explicitly approved way of getting objects, changing them, making new ones, etc.

This might look like this:

do
	local NPCs = {}
	-- This hides NPCs as a variable after the `end` for this `do` (since it's local)
	-- functions are global, so they can be used outside of the `do end`

	function isNPC( thing )
		for _, obj in pairs(NPCs) do
			if obj == thing then
				return true
			end
		end
		return false
	end

	function newNPC( npc )
		if not isNPC( npc) then
			table.insert(NPCs, npc)
			-- Now do whatever you want to do it:
			Instance.new("NumberValue", npc).Name = "Health"
		end
	end

	function removeNPC( npc )
		assert( isNPC(npc) )
		for i = #NPCs, 1, -1 do
			if NPCs[i] == npc then
				table.remove(NPCs, i)
			end
		end
		assert( not isNPC(npc) )
	end

	function getNPCsNear(point, distance)
		local result = {}
		for _, npc in pairs(NPCs) do
			if (npc.Torso.Position - point).magnitude < distance then
				table.insert(result, npc)
			end
		end
		return result
	end
end

The other nice result of this is that you provide explicit, clear ways that you're allowed to get information.

For instance, in the above, there is no (reasonable) way to get a list of all NPCs.

That's a good thing -- there's no good reason some random part of your script should be able to affect the entire world.

At the same time, you're provided with a neat little function to get everything nearby -- also eliminating the need for that code to ever appear twice in your code elsewhere.

This discussion is preserved as it was. New answers, comments, and votes are closed.