Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
4

Problem with metatables and workspace?

Asked by 8 years ago

So I'm having trouble with this bit of code. I'm trying to make a metatable with it's __index metamethod referencing the Workspaceservice. 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.

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 4Bros 550 — 8y
0
for instance: print(getmetatable(workspace)) and print(getmetatable(getfenv(workspace.FindFirstChild))) returns "The metatable is locked" 4Bros 550 — 8y
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. ScriptGuider 5640 — 8y
0
I think I see the issue. I'm gonna test just in case. adark 5487 — 8y

1 answer

Log in to vote
5
Answered by
adark 5487 Badge of Merit Moderation Voter Community Moderator
8 years ago

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.

0
Thank you very much, this makes total sense! Accepted and upvoted. MightyQuestionAsker 297 — 8y
Ad

Answer this question