Add unique composition of methods (function) to metatable? .self not working correctly

To start, I want to be able to add whatever methods I choose to a specific metatable. I don’t want to use inheritance with BaseClasses or SuperClasses because all my metatables are unique and don’t share the same composition of methods.

For example, Object A has the methods called :Destroy() and :Update().
Object B has the methods called :Destroy() and :Fling().
Object C just has the method :Fling().
Object D just has the method :Move().

This is primarily why I think any inheritance technique won’t work for me or my project. The objects have some methods in common, but some objects don’t have any in common with other objects.

Here is what I have so far:

--Object D, in a Module Script
local ServerScriptService = game:GetService("ServerScriptService")
local Functions = ServerScriptService:WaitForChild("Functions")

local Class = {}
Class.__index = Class

function Class.New()
	return setmetatable({
		Position = Vector3.new(3532,523,512),
		
		Utility = {
			Move = require(Functions:WaitForChild("Move"))
		}
	}, Class)
end

return Class
--Move Utility, in a Module Script
local Utility = {}
Utility.__index = Utility

function Utility:Move()
	self.Position = Vector3.new(1,1,1)
end

return Utility
--Placeholder script that uses these components
local a = require(script.Parent) --Object D, Module Script

local b = a.New()
b.Utility.Move:Move()

The issue here is that the Utility:Move() function doesn’t use self correctly? The Utility:Move()'s self is the Move Utility table with the :Move() function inside of it. I don’t know how to make the self be switched to Object D.

The colon is what passes the object to the self argument. Self is always going to be what’s behind the colon. You’re calling Move on b.Utility.Move, so self is exactly that. Instead, you want to structure your object so that you call Move directly on the object

local ServerScriptService = game:GetService("ServerScriptService")
local Functions = ServerScriptService:WaitForChild("Functions")

local Class = {}
Class.__index = Class

function Class.New()
	return setmetatable({
		Position = Vector3.new(3532,523,512),
		
		Move = require(Functions:WaitForChild("Move")).Move
	}, Class)
end

return Class
--Placeholder script that uses these components
local a = require(script.Parent) --Object D, Module Script

local b = a.New()
b:Move()
2 Likes

This works great! :slight_smile: I was starting to give up hope and I was just gonna put all my functions into one shared metatable, lol.

One thing though,

function Class.New()
	return setmetatable({
		Data = {
			Position = Class.Constants.DistantVector,
		},
		
		Methods = {
			Move = require(Methods:WaitForChild("Move")).Move,
		},
		
	}, Class)
end

If I wanted to organize my metatable into smaller tables, how could I avoid the attempt to call missing method 'Move' of table error?

-- The edited placeholder script.
local a = require(script.Parent)
local c = {}

local b = a.New()
print(b.Data.Position)
b.Methods:Move() --I think the error is here, cause I'm calling :Move() on a table instead of on the object, however I don't know how else to access Methods.Move.
print(b.Data.Position)

Unfortunately, this is not possible; notice how you’re calling Move on b.Methods. Self in this case is going to be b.Methods rather than your object. Organizing methods into a folder of an object is not conventional either. It defeats the purpose of creating objects in the first place

Yea now that I think of it, it does.

function Class.New()
	return setmetatable({
		Data = {
			Position = Class.Constants.DistantVector,
		}
		
	}, Class)
end

Class.Move = require(Methods:WaitForChild("Move")).Move

For anyone reading in the future, I’ve decided to go with this type of formatting for my code. This allows me to add operator methods like :Move(), :Fling() and so on without having it be incredibly messy or me having to add self as a function parameter.

Thanks dukzae for all the help. :slight_smile: