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

Problem with metatables and workspace?

So I'm having trouble with this bit of code. I'm trying to make a metatable with it's __index metamethod referencing the Workspace service. I'm doing this to create custom methods on workspace, while at the same time keeping all it's other properties / methods accessible with the metatable.

Here's what I have:

-- _workspace is the table of custom methods
local _workspace = {}

-- custom "GetName" method
function _workspace:GetName()
	return "Hello, I'm the workspace"
end

-- Here I overwrite the global "workspace" variable, with a table containing custom methods, but a metatable referring to it's original self.
local workspace = setmetatable(_workspace,{
	__index = workspace
})

-- Now if I said...
print(workspace:GetName()) -- It prints "Hello, I'm the workspace"

-- However... If I were to use a default method like GetChildren...
print(workspace:GetChildren())

-- It errors.

The problem?

So calling my custom method on the new overwritten "workspace" variable works, but it seems to cause an error for every other single method that already existed on the workspace.

Here's the error I get when I call something like "GetChildren" on the workspace after applying my code:

19:02:38.753 - Expected ':' not '.' calling member function GetChildren

Which is weird, because I do have the original workspace service referenced with the __index metamethod, and I am calling it with : , not .. So what's wrong?

If anyone out there can provide some insight on this, I'd be very grateful. It's been driving me crazy.

4 comments

0

i dont think you can access or overwrite the environment of any of roblox's methods in which they reside such as findfirstchild or getchildren but i might be wrong

0

for instance: print(getmetatable(workspace)) and print(getmetatable(getfenv(workspace.FindFirstChild))) returns "The metatable is locked"

0

He's not modifying them. He's creating a metatable that references methods from them, while including custom ones. This is done with object wrappers all the time.

0

I think I see the issue. I'm gonna test just in case.

1 answer

✓ Accepted answer

Alright, this one's a bit tricky.

What's happening is workspace.GetChildren is expecting workspace as the first argument, and is instead getting your custom table, which is not what we want.

To fix this, we have to manually call the method of workspace we're trying to access:

local _workspace = {}

function _workspace:GetName()
    return "Hello, I'm the workspace"
end

local ws = game:GetService("Workspace")
local workspace = setmetatable(_workspace,{
    __index = function(_, prop)
		return function(_, ...) --This ignores the first argument to the __index'd function call: your _workspace table.
			return ws[prop](ws, ...)
		end
	end;
})

print(workspace:GetName())
print(workspace:GetChildren())

There are two issues with this, though: accessing and setting properties of workspace is not possible via your Table!

To fix this, we have to change __index slightly and add a __newindex to track properties being set:

local _workspace = {}

function _workspace:GetName()
    return "Hello, I'm the workspace"
end

local ws = game:GetService("Workspace")
local workspace = setmetatable(_workspace,{
    __index = function(_, prop)
		if type(ws[prop]) == "function" then
			return function(_, ...) --This ignores the first argument to the __index'd function call: your _workspace table.
				return ws[prop](ws, ...)
			end
		else --Correctly return properties
			return ws[prop]
		end
	end;

	__newindex = function(_, prop, val) --Handle setting workspace properties.
		if ws[prop] ~= nil then -- we explicitly check for nil here because `false ~= nil`
			ws[prop] = val
		end
	end;
})

print(workspace:GetName())
print(workspace:GetChildren())
print(workspace.AllowThirdPartySales)
workspace.AllowThirdPartySales = true
print(workspace.AllowThirdPartySales)

There are a few issues with this, namely properties that have an initial nil value, but that's beyond the scope of this answer.

1 comment

0

Thank you very much, this makes total sense! Accepted and upvoted.

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