OOP: Using 'self'?

Quick question: how can I structure the following so ‘self’ does not have to be defined in Function?


Current:

command = {
	Name = "test101";
	Aliases	= {};
	Prefixes = {settings.Prefix};
	Rank = 1;
	RankLock = false;
	Loopable = false;
	Tags = {};
	Description = "";
	Contributors = {};
	--
	Args = {};
	Function = function(self)
		print(self.Name)
	end;
	--
};

command:Function()

test101


Target:

Function = function()
	print(self.Name)
end;

Only a few commands require the self variable so it seems slightly redundant to have to define it every time.

Thanks.

1 Like

In Lua, the following are functionally equivalent:

Class.Function = function(self)
	print(self.Name)
end

function Class.Function(self)
	print(self.Name)
end

function Class:Function()
	print(self.Name)
end

With the colon, self is created as a variable implicitly and doesn’t require the declaration in the arguments. It is similar for calling where Workspace.GetChildren(Workspace) is functionally equivalent to Workspace:GetChildren(). For your example, you would want to move to something like this:

command = {
	Name = "test101";
	Aliases	= {};
	Prefixes = {settings.Prefix};
	Rank = 1;
	RankLock = false;
	Loopable = false;
	Tags = {};
	Description = "";
	Contributors = {};
	--
	Args = {};
	--
};

function command:Function()
	print(self.Name)
end

command:Function()
5 Likes

If the command was structured as a Table instead of a Dictionary, would this still be possible? For example:

{
	Name = "test101";
	Aliases	= {};
	Prefixes = {settings.Prefix};
	Rank = 1;
	RankLock = false;
	Loopable = false;
	Tags = {};
	Description = "";
	Contributors = {};
	--
	Args = {};
	Function = function(self)
		print(self.Name)
	end;
	--
};
{...};
{...};

I don’t believe it is possible since it is impossible to use the colon syntax inside a table. Having the self (or _ to show it is not being used) would be required for every function without redesigning how it is set up.

1 Like

Appreciate the help! I think I’ll keep self as the final parameter for now then to avoid the repeated unnecessary use.

If you are passing multiple parameters, keep in mind you will need to format your functions a bit differently since self is implicitly used as the first argument since calling something with Class:Function(Arg1,Arg2,...) is the same as calling Class.Function(Class,Arg1,Arg2,...). Ex:

local Command = {
	Name = "Test Command",
	Function = function(Arg1,Arg2,self)
		print(self.Name)
	end,
}

Command.Function("Some string",5,Command)
1 Like

Got this covered - I’ll be doing the following instead:

command.Function(speaker, args, command)
1 Like

If you plan on making multiple commands, you can avoid including the function in every command object by using a __index metamethod/metaproperty that references a table which has the shared functions between all command objects.

local CommandAPI = {}
function CommandAPI:Function()
    print(self.Name)
end

local function Command(struct)
    return setmetatable(struct, {
        __index = CommandAPI
    })
end

local cmd_1 = Command {
	Name = "test101";
	Aliases	= {};
	Prefixes = {settings.Prefix};
	Rank = 1;
	RankLock = false;
	Loopable = false;
	Tags = {};
	Description = "";
	Contributors = {};
	--
	Args = {};
	Function = function(self)
		print(self.Name)
	end;
	--
};
local cmd_2 = Command {...};
local cmd_3 = Command {...};

You could also store the Command metatable for efficiency, but I’ve inlined it for simplicity.

1 Like