The Self Keyword

I am currently learning OOP and I’d like to ask what the Self keyword means, what it’s used for and why I’ve searched for definitions of it but it’s very confusing.

2 Likes

self is widely recognised across many programming languages in OOP. It’s used to refer to the current object you are editing. For example, when creating an object through a class constructor, you would likely use self to store the object.

local self = setmetatable({}, Class)

It’s just like naming conventions (is a naming convention?) and indicates to others reading the code that it’s an object. When using colon notation, self is automatically defined as the first parameter.

local Class = {}
Class.__index = Class

function Class:SomeMethod()
    print(self) --outputs all items of the class as they were created in Class.new
end

function Class.new(): ClassType
    local self = setmetatable({}, Class)
    self:SomeMethod() -- same as doing self.SomeMethod(self)

    return self
end

export type ClassType = {
    ["new"]: () -> (ClassType),
    ["SomeMethod"]: (self: ClassType), -> (nil)
    --regardless whether we did self:ClassType there, self would still be defined.
}

return Class

Here’s some more information from a post which has a similar question?

Self and how to use it

If you have any more questions, please ask! I don’t know how well I’ve explained it here.

So say I created an Class called Enemy’s and one of them was a Zombie. When I use a function for the zombie to damage the player and I’m getting the zombies damage amount I would not use Zombie.Damage I would use Self.Damage?

Yes, if you wanted to change the damage of that one individual zombie you would use the parameter holding the zombie object and not the class name.

function Class:SomeMethod()
end

When creating the functions we use the class name to define it. This is because setmetatable in the class constructor will cause the object to inherit everything from the class, including these methods.

Like i said above if you want to change an item within an object use the variable that represents it and not the class name. Using the class name would change that thing for all future objects.

Sorry but I dont really understand what your saying in the 2nd and 3rd paragraph

self is just a variable that points to a method’s table.

local t = { k = 1 }

function t:print()
    print(self.k) -- 'self' points back to 't'
end

It’s not tied to OOP specifically; OOP just uses it a lot.

You use it because with OOP, you create multiple objects that behave differently from each other.

If you just used t on it’s own, you will be pointing back to the original table every time. In OOP, you create a unique table that behaves on it’s own without being tied to the original one, and self is how you access the unique table.


local t = {}
t.__index = t

function t.new()
   return setmetatable({k=2}, t) --> create a new object
end

function t:print()
   print(self.k) --> prints '1' because the newly created object has it
   print(t.k) --> 'k' doesn't exist in the original 't' table, so this will print nil
end

-- Usage

local j = t.new() --> make the new object
j:print() --> call the method on the new object

-- Likewise, if you did
t:print()
-- this will print 'nil' twice

TL;DR: self is basically a variable name that gets a special syntax highlight because it should only be used for OOB.

I Like Reading:
self is a variable that is typically returned at the very end of a SomeClass.new(args) function. Let’s say we made a car factory with this module script.

--somewhere in a module script...
local Car= {}
Car.__index = Car

function Car.new(numPassengers, type, color)
    local self = setmetatable({}, Car)
    
    self.passengers = numPassengers
    self.type = type
    self.color = color
    return self
end

return Car

Alright, let’s go over this piece of code.
Imagine that this is your car factory. It contains the instructions on how to make a car. Customers (scripts) can ask the car factory “hey I want a car that can hold 7 people, is a van, and is lime green”.

local myNewCar = Car.new(7, "van", rgb(0,255,0))

The car factory says “ok, here’s your car”.
return self

The customer (your script) and the car factory (the module script) call the car by a different name.
YOU call it myNewCar and the FACTORY calls it self. In fact it individually calls all the cars it has ever made self.
If this were real life you would call your car “My Car”; It belongs to you.
The car factory sees it as the customer’s car, whoever the customer happens to be is not important to the factory. The car factory sees many different customers every single day and doesn’t have enough time to care.

So:
YOU call it
myNewCar
the factory calls it self

Still with me? Cool.
Now you might want to drive your car.

myNewCar:Drive

Your car has a method (a function) for that, called Drive.

--somewhere in the same module script as before
function Car:Drive(speed)
    --driving code
end

All of these methods are sent back when we return the Car module, and can be accessed by you, the customer/driver. When YOU (the customer/driver) call one of these methods, it executes only on YOUR car.

1 Like

You might not be understanding what the __index metamethod does in a metatable.

local Class = {}
Class.Property = "Class"

function Class:DoAThing()
   print(self.Property)
end

Class:DoAThing() --> Class

local instance = {}
instance.Property = "Instance of Class"
setmetatable(instance, { __index = Class })

instance:DoAThing() --> Instance of Class

When indexing a field in a table (a colon is just a special way to index a function). If it doesn’t exist and the table’s metatable has a __index field defined, it will check that table as well. This is how instance finds the DoAThing method above.

Because self refers to the table the method was called on, when I call Class:DoAThing(), it will index the Class table. When I call it on instance, it will index the instance table.

To add on to this,

instance:DoAThing()

--is the same as

instance.DoAThing(instance)

-- where

function Class:DoAThing()

-- is the same as 

function Class.DoAThing(self)

not metaphorically, these are the exact same in lua. A colon is just passing the table as its first parameter and naming it self.

Calling a : method with a . will rename the first parameter to self without explicitly declaring it.

function Class:DoAThing()
    print(self.Property)
end

instance.DoAThing( {Property = "Hi!" } ) --> Hi!

I already know all about metatables and metamethodes especially what __index does dw.

So Self basically represents the Table your using that function on?

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.