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

Can someone provide an explanation of Meta Method wrapping code example?

Asked by
Gunt_r 31
4 years ago

Hi everyone,

I'm having quite a bit of trouble understanding how this piece of code works. I understand that there is comments to help understand what the scripter is doing but frankly i cant seem to make sense of it. The code above was created by scriptguider. The link to the original post can be found here: https://scriptinghelpers.org/questions/39391/wrapping-instances-with-robloxs-lua

In particular, i need help understanding:

  • Why interface and behaviour were specifically chosen as the name of the variable in the function.

  • How the local part interacts with the part in the WrapPart function.

  • What behavior.__index = part does

  • What function behavior:__newindex(key, value) ....... end does

  • How return setmetatable(interface, behavior) interacts with the rest of the code.

-- Create part first
local part = Instance.new("Part", workspace)

local function WrapPart(part)
    local interface = {}
    local behavior = {}

    -- Object interface --
    interface.BirthTime = os.time() -- Create property

    -- Interface behavior --
    behavior.__index = part -- Set reference to this object to part

    function behavior:__newindex(key, value)
        part[key] = value -- Set new index of this object to new index of part
    end

    -- Return new interface
    return setmetatable(interface, behavior)
end

-- Pass part to wrapper
local wrappedPart = WrapPart(part)

-- As you can see, we can access both our new property, and all the part's other properties. Giving us the illusion we added something to this object.
print(wrappedPart.BirthTime) -- > Timestamp
print(wrappedPart.Name) -- > "Part"

Thanks for the help.

2 answers

Log in to vote
2
Answered by 4 years ago
Edited 4 years ago

Why interface and behaviour were specifically chosen as the name of the variable in the function.

Interface simply refers to the functionality that you can use. behavior holds the metatable, which dictates the behaviour of the table.

How the local part interacts with the part in the WrapPart function

The local part is passed in to the WrapPart function; the local variable part could be just as easily moved to after the WrapPart function is declared.

What behavior.__index = part does

Since behavior becomes the metatable for interface, this tells Lua that whenever you try to access a key in interface that does not have a value, check for the key in part instead. You can look up what metatables do for more information:

You can set __index to a table or a function; if you set it to a function, Lua will run that function to get the value to return.

setmetatable(interface, behavior) tells Lua that you want behavior to be interface's metatable; the setmetatable function also returns the first argument you gave it (interface in this case). Thus, local wrappedPart = WrapPart(part) effectively assigns interface to wrappedPart.

__newindex is the same idea, but for assignment. If, at the end of the script, you say wrappedPart.Name = "Hello", "Name" would not exist on the interface/wrappedPart table (both interface and wrappedPart reference the same table), so the function assigned to __newindex has code to redirect this assignment to the original part passed in to WrapPart. The final results is that the original part would have the new name.

(To be clear, function behaviour:__newindex(key, value) ... end is identical to behaviour.__newindex = function(self, key, value) ... end)

In the code (line 26) wrappedPart.BirthTime, BirthTime is already defined on the table (this is done on line 9), so __index is not involved. However, on line 27, "Name" was never defined on the table, so without a metatable, wrappedPart.Name would return nil -- but since we have a metatable with __index defined, Lua checks (in our case) the original Part, effectively performing part.Name (which is why it prints out "Part").

Ad
Log in to vote
0
Answered by
Gunt_r 31
4 years ago

I get most of it now but i still dont understand a few things.

How is it that the parameter of the WrapPart function, in this case, "part", can be the same name as the local "part" = Instance.new. I cant fully know that i understand lines such as behavior.__index = part because i cant tell which "part" it is talking about. Would it change anything if i changed the local "part" = Instance.new. to something like local "block" = Instance.new? Would it matter if i changed the name of the parameter in the function to something not defined yet? If the parameter of the function is simultaneously defined as a variable, how does that work?

Does calling __newindex on the list through "behaviour" add an item to "Interface"? Is that correct? I need clarification for exactly where that new index item is defined.

I have a few more questions still but hopefully those will be answered when someone explains the deal with the "part" variable/parameter.

Answer this question