Metachain
By @avodey (my main account)!
Get Module
Summary (v1.1.0)
So, you use object-oriented programming (OOP)? You may use some metatable magic to create basic inheritance:
local Super = {}
local Object = {}
Object.__index = Object
function Super.new()
local self = {}
self.Coins = 0
return setmetatable(self, Object)
end
function Object:Run()
print("Ran", self.Coins)
end
local test = Super.new()
test:Run() --> Ran 0
Super.new()
creates an object that, when you index it and comes out as nil, it asks Object
for the information instead. You can see that the Run
method is called this way.
But what if you wanted to inherit from multiple libraries and/or objects? That’s what this module is for! It will allow you to have a table inherit a library, or another object. You’ll also learn that it’s possible to make specific methods private, which makes them inaccessible through the chain. All the API will be explained later, but for now, let me go over some use cases.
Use Cases
1: Library Extension (Inheritance)
This use case will let you add more methods to your objects.
View Examples
-- module 1:
local Metachain = require(game.ReplicatedStorage.Modules.Metachain)
local Super = {}
local Wrapper = {}
Wrapper.__index = Wrapper
local Object = {}
Object.__index = Object
--\\ Public Methods
function Super.new()
local self = Metachain.new()
self.Component = require(module2).new()
self.Cache = {}
self:AddLibrary(Wrapper)
self:AddLibrary(self.Component)
return self
end
--\\ Wrapper Methods
function Wrapper:Start()
print("Started")
end
function Wrapper:End()
print("Ended")
end
-- module 2:
local Super = {}
local Object = {}
Object.__index = Object
function Super.new()
local self = setmetatable({}, Object)
self.Object = Instance.new("Frame")
return self
end
--\\ Instance Methods
function Object:Update(dt)
print("Updated")
end
This code is a bit long, so let me explain. Objects created by Module 1 inherit an object created by Module 2. If you try calling module 2’s methods, it will work! Let’s test it:
-- module 1:
local test = Super.new()
test:Start() --> Started
test:Update(0) --> Updated
test:End() --> Ended
It works! This use case was primarily the reason I created the module. However, I also made it for the next use case, which allows you to inherit other objects.
2: Object Extension (Polymorphism)
This use case will let you derive an object from another.
View Examples
local Metachain = require(game.ReplicatedStorage.Modules.Metachain)
local Data = {
Coins = 10,
Gems = 10,
}
local Inventory = {
Units = {
{Name = "Solider"}
},
Items = {
{Name = "Star of Nobility"},
},
}
local UserData = Metachain.new(Data)
print(UserData.Units) --> nil
UserData:AddObject(Inventory)
print(UserData.Units) --> {{Name = "Solider"}}
print(UserData.Items) --> {{Name = "Star of Nobility"}}
The code above demonstrates how you can inherit another object. Let me explain the code.
1: Require the Metachain module
3: Get the user’s currency somehow
8: Get the user’s inventory somehow
18: Make a chain object using the user’s data
20: Print the user’s units through the chain, which prints nil
22: Add the Inventory object to the chain
24: Print the user’s units through the chain, which prints a table
25: Print the user’s items through the chain, which prints a table
As you can see, after the AddObject
method is called, you can now access Inventory
through UserData
! An important distiction needs to be made regarding AddObject
and AddLibrary
Chain:AddObject(any)
Allows accessing the object from the chain.
self
is the accessed object.
Chain:AddLibrary(any)
Allows using the library in the chain.
self
is the chain.
AddLibrary
is a substitute for using setmetatable({}, Object)
. Calling methods using a :
will pass self as the chain object. AddObject
has self as the added object itself, and not the chain! Libraries must be tables, while objects can be tables and instances.
API
Super.new(table): Chain
Creates a new metachain object. The value is returned is not the same table with a metatable attached. Instead, it’s a new table that points to it!
Chain:AddObject(value: table|Instance, only: “Get”|“Set”?): Chain
Adds a new object reference to the chain.
only:("Get"|"Set")
Only allows for getting, or setting values.
only:(nil)
Allows for both setting and getting values.
Chain:AddLibrary(value: table): Chain
Adds a new library reference to the chain.
Chain:AddWith(value: table|Instance, only: “Get”|“Set”?): Chain
Adds a new reference to the chain. Automatically decides whether it is a library or object.
only:("Get"|"Set")
If determined as an object, only allows for getting, or setting values.
only:(nil)
Allows for both setting and getting values.
Chain:StopChain()
Removes all the chain methods to remove interference.
Conclusion
I’d love to hear your feedback! If you have questions, or find a bug, you should leave a reply!