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

How to make a table inherit the functions of the table it's contained in?

Asked by 7 years ago

Hi, I'm currently creating a very general open source inventory system for everyone to use, but i've come across a problem. I've created a modulescript called ItemDB where I keep track of all items and their properties. It looks like this right now:

itemDB = {
    ["TestBrick"] = {
        Image = "",
        Properties = {"pickupable"},
        Path = game.ReplicatedStorage.TestBrick, 
        hasProperty = function(self, property)
            for i, p in pairs(itemDB["TestBrick"].Properties) do
                if p == property then
                    return true
                end
            end
            return false
        end 
    };

}

return itemDB

So currently I can do

itemDB["TestBrick"]:hasProperty("pickupable") 

which will return true, which is great! However this is only single function, which is several lines long, and every item will need access to several functions. ItemDB is gonna be very long with a minimal amount of items. I'd love to put the hasProperty function in the itemDB table itself, instead of putting it in every item's table. If I put the function in the ItemDB table and then call it on ["TestBrick"], i get the following error:

 ReplicatedFirst.PickUpItems:9: attempt to call method 'hasProperty' (a nil value)

Which makes sense, since hasProperty is indeed not present in ["TestBrick"]. Is there any way to get this to work the way I want it? Like, a way to make ["TestBrick"] inherit all functions of ItemDB?

0
Yeah, like @Epidemiology explained you could create a separate table with the functions and then use__index to link it. AstrealDev 728 — 7y

1 answer

Log in to vote
0
Answered by 7 years ago
Edited 7 years ago

One way to do this would be to use metatables and have each table in itemsDB have the same __index table in the metastable.

The __index metamethod is called is called/indexed every time that indexing the table fails

local t = {}
local f = {}
f.Value = 3
print(t.Value) -- this will print "nil"
setmetatable(t, {__index = f})
print (t.Value) -- this will print "3"
-- 'Value' is not in 't' so it looks in the index of 't'
-- So, t.Value is f.Value, which is 3

Implementing this idea, you could do something like:

local itemindex = {
    -- Contain all properties and methods that members of itemDB should have
}



setmetatable(itemDB, { -- Now to add it to new tables.
    __newindex = function (tab, index, value) -- Runs every time items are added to the itemDB table with the assignment operator
        setmetatable(value, {__index = itemindex}) -- Set the index to itemindex
        rawset(tab, index, value) -- Rawset ignores __newindex, without this it would cause an infinite loop.
    end
})
 -- However this will only work with the assignment operator
-- meaning that __newindex is not called when table.insert is used.

For tables that are manually put in itemDB like

itemDB = {
    Item1 = {},
    Item2 = {},
}

you would need to manually specify the index like

itemDB = {
    Item1 = setmetatable({}, {__index = itemindex}),
    Item2 = setmetatable({}, {__index = itemindex}),
}

Or you could do (if using the __newindex metamethod)

itemDB = {}
itemDB.Item1 = {}
itemDB.Item2 = {}
Ad

Answer this question