What is ".self"?

Hi, i’ve seen some people use .self especially in modules and i’m just wondering what it is and why it is used?
~~
for example Party system help

3 Likes

self is basically a thing you can use in OOP to reference the subject, this is useful to access its properties. e.g.

local Car = {}
Car.__index = Car

function Car.new(model, color) -- Making a new car object
  local NewCar = setmetatable({}, Car) 
  NewCar.Model = model
  NewCar.Color = color
  return NewCar
end

function Car:Properties()
  return {self.model, self.color} -- Self is referencing an object we made
end

-- Separate script
local CarModule = require(carmodule)
local MyCar = Car.new("Firebrand", "Red")

print(MyCar:Properties()) -- Prints {"Firebrand, "Red"}

I hope this helped.

8 Likes

Oh thanks for the example,
When you put lua print(MyCar:Properties()), does the Car:Properties() function know to return the model and colour of MyCar because you called the Properties function with the variable “MyCar” lua MyCar:Properties() instead of “Car” Car:Properties()

1 Like

Here’s another random and simple example to demonstrate:

local object = {
  PropertyA = 120,
  AddToPropertyA = function(self, val: number)
    self.PropertyA += val
    return self.PropertyA
  end,
}

print(object:AddToPropertyA(15)) -- > 135
print(object.AddToPropertyA(object, 15)) -- > 135
2 Likes

Here you go, there’s a bit more info regarding the “self” parameter here.

and also here.

https://www.lua.org/pil/16.html

2 Likes

The examples here were too overcomplicated so I will give you my explanation.

You use self if you’re calling an object method and want to refer to that object.

These two are equivalent

object:function() == object.function(object)

Example:

local car = {__name = "car name"}

function car:test()
    -- automatically references `self` to the `car` object without a need to define it explicitly
    print(self.__name)
end

function car.test2(self)
    print(self.__name)
end

car:test()
car.test(car)
car.test2(car)
car:test2()

Output:

car name
car name
car name
car name
6 Likes

Thank you, let’s say if I want to refer to each different players’ cars? so e.g. Player1’s car, then Player2’s car how can I get that specific player’s car object?

In this case you would need to create a table and store each players car object in that table.

1 Like

A more in-depth explanation of self.

When writing a function in a table, you can write it like this:

local module = {}

function module.new()
	--blah blah blah
end

return module

This is the same thing as writing it like this:

local module = {
	new = function()
		--blah blah blah
	end
}

return module

When using a colon : in functions, such as in the case of function module:example(), the colon is often described as “syntax sugar” (although it’d be more accurate to call it “syntactic sugar”, I digress). What this means is that it is not really needed and only exist for the purpose of looking good and simplifying the code.

The : in the declaration is basically passing the table itself as the first parameter in the function. For example

function module:example()
	--other code
end

is the same thing as:

function module.example(module)
	--other code
end

The module parameter in the second example is the module itself. That is why the self keyword is aptly named self. You may still be wondering how these two example are the same. In that case, if I were to call each of them, then I’d have to do it in two separate ways, like so:

module:example() --first example

module.example(module) --second example

Hopefully, I explained it in a way that was understandable. As a parting gift, here’s a working example of a script that utilizes each method:

local module = {}


function module:example1()
	print("Self1: ",self)
end

function module.example2(self)
	print("Self2: ",self)
end

module:example1()
module.example2(module)

It will print the table and each function within it in the console.

2 Likes

Thank you very much, I’d like to say I appreciate it i’ve been seeing you helping me a lot on the questions I asked, thank you truly for that :smiley:

I’m just wondering on how I should go about creating a party system and if I should use OOP / .self with it?

Self Explanation: What is the self keyword in Lua? - Roblox Studio - YouTube

OOP Intro: https://www.youtube.com/playlist?list=PLXSd5YZgxaXSjGBMAn5FqdtZIG-3Gsp4z

1 Like

Given the example party system you used, OOP would be the best method for creating the parties. Whether or not you use the self keyword depends on whether you actually need it. Take for example, a math module with a function that returns whether or not a number is even:

local module = {}

function module.isEven(x : number)
	return math.abs(x)%2 == 0
end

return module

In this example, there is no reason it needs the self keyword so it isn’t used. However, in a party object, you will most likely have a Members property that has a list of all the players in the party. If theoretically we had a function that returns a random member in the party, it will need access to the members in it. So, the function might be written like this:

local Party = {}

function Party:IsMember(player) : (boolean, number?)
	local index = table.find(self.Members, player)
	
	return (index~=nil), index
end

function Party:AddMember(player : Player) : ()
	table.insert(self.Members, player)
end

function Party:RemoveMember(player : Player) : ()
	local isMember : boolean, index : number? = self:IsMember(player)

	if isMember and index then
		table.remove(self.Members, index)
	end
end

function Party:GetRandomMember() : Player
	return self.Members[math.random(#self.Members)] :: Player
end

return { -- returns a table with the constructor functions
	new = function(players  : {Player})
		local party = setmetatable({}, Party)

		party.Members = table.move(players,  1, #players, 1, {}) :: {Player}

		return party
	end
}

Because this function needs access to all the current members in the party, we use the self keyword. I also added several other function that you might see in a party system.

However, the ones that I are supposed to be private to the object are indexed with a underscore (_) before the name. This is because private and public variables are a concept in OOP, even though they aren’t possible in Lua through easy means (you have to use a proxy and weak references). It’s more for organization than anything else.

Although Roblox is going to release a feature that allows the developer to specify which methods can be seen publicly (outside the module) using the typechecker.

If you do not understand OOP yet, you can take a look at the following resources:

2 Likes

Thanks, how would I clear a car that was created? If i wanted to remove it later

In that case you could either clear all the values in the car object and then remove the reference you have to it, or just remove the reference you have to it.