Why does this work? (metatables/wrapping)

Hello!

When I script, I like to know why what I do works and I’ve run into that issue where I don’t know what I’m doing and I don’t know why this works.

I recently had an issue where I couldn’t find out how to get arguments through __index but I was able to find a solution for that, but I don’t understand why it works.

local meta = {
			__index = function(tbl, key)
				if type(currentDummy[key]) == 'function' then
					return function(tbl, ...) -- here, I don't get why I have to return a new function whose first arguments are tbl and then I have to do the vararg if that makes sense
						return currentDummy[key](currentDummy,...) -- I don't understand how the ... gets assigned a value
					end
				else
					return currentDummy[key]
				end
			end;
			__newindex = function(tbl, key, value)
				if currentDummy[key] ~= nil then
					currentDummy[key] = value
				end
			end;
		}
		return setmetatable(funcs, meta)

Basically, when I do :WaitForChild() on the metatable, it works as intended, why?

I am finding it difficult to understand from the script provided how it works too.
Where is currentDummy defined?

currentDummy is a model outside of the metatable, let me get the whole thing:

    ['CreateDummy'] = function(self)
		local currentDummy = dummy:Clone() -- where currentDummy is defined
		local humanoidRootPart = currentDummy:WaitForChild('HumanoidRootPart')
		local humanoid = currentDummy:WaitForChild('Humanoid')
		currentDummy.Parent = dummyFolder
		local pathContainer = currentDummy:WaitForChild('Path')
		pathContainer.Value = pathfindingService:CreatePath()
		local funcs = { -- added functions
			['MoveToActive'] = false;
			['Status'] = 'Roaming';
			['Instance'] = currentDummy;
			['GenerateRandomPoint'] = function(self, radius)
				local currentPos = humanoidRootPart.Position
				local atts = 0
				repeat 
					local randomPos = currentPos + Vector3.new(math.random(-radius, radius), 0, math.random(-radius, radius))
					atts += 1
					print(atts)
					pathContainer.Value:ComputeAsync(currentPos, randomPos)
				until pathContainer.Value.Status == Enum.PathStatus.Success
			end;
			['PlayPath'] = function(self)
				self.MoveToActive = true
				for i,v in ipairs(pathContainer.Value:GetWaypoints()) do
					local currentWaypoint = Instance.new('Part')
					currentWaypoint.Parent = debugFolder
					currentWaypoint.Material = Enum.Material.Neon
					currentWaypoint.Size = Vector3.new(1,1,1)
					currentWaypoint.CanCollide = false
					currentWaypoint.Shape = Enum.PartType.Ball
					currentWaypoint.Anchored = true
					currentWaypoint.Position = v.Position
					currentWaypoint.CanCollide = false
					self.Dots[#self.Dots + 1] = currentWaypoint
				end
				for i,v in ipairs(pathContainer.Value:GetWaypoints()) do
					if self.MoveToActive then
						humanoid:MoveTo(v.Position)
						print('mt', v.Position)
						humanoid.MoveToFinished:Wait()
						print('mtf')
					else
						break
					end
				end
				pathContainer.Value = pathfindingService:CreatePath()
			end;
			['CancelPath'] = function(self)
				self.MoveToActive = false
			end;
			['DestroyDots'] = function(self)
				for i,v in pairs(self.Dots) do
					v:Destroy()
				end
			end;
			['Dots'] = {}
		}
		local meta = {
			__index = function(tbl, key)
				if type(currentDummy[key]) == 'function' then
					return function(tbl, ...)
						return dummy[key](currentDummy,...)
					end
				else
					return currentDummy[key]
				end
			end;
			__newindex = function(tbl, key, value)
				if currentDummy[key] ~= nil then
					currentDummy[key] = value
				end
			end;
		}
		return setmetatable(funcs, meta)
	end;

So line two in the second script shows currentDummy being created via clone of dummy I believe I need to see what dummy is.
For me to understand what the construct of the table is I need to see its construction.
You may feel I am wasting your time but if you need my help then please supply more details.

Basically,

instance:WaitForChild("someChild")

works the same way as

local WaitForChild = instance.WaitForChild -- here, WaitForChild is a function
WaitForChild(instance, "someChild") -- here, you call the function

You are still indexing the table.

return function(tbl, ...)
	return currentDummy[key](currentDummy,...)
end

It appears like it’s a proxy table. tbl would be the table itself. Since you want it to be the instance, you have to replace the first argument with the dummy instance, to call WaitForChild on it.

1 Like