I’m trying to learn OOP and self is used here in a way that I don’t understand.
Wouldn’t boost do nothing as there is nothing inside of the brackets for newcar:Boost()? As that is what self is automatically assigned as when using colons?
I’m trying to learn OOP and self is used here in a way that I don’t understand.
using colons are fine
I don’t really know how to use self
thought but try to read this
Self just references the table you’re calling on:
In this case, self is the table newcar
.
When you construct a new object, you are assigning its metatable __index to the Car table, which is where you are storing your methods (functions). Self is simply just a reference to the specific table (the object).
Why is this tho? Please explain
What is the object in this case?
When they said:
local newcar = Car.new(Vector3.new(1, 0, 1), "Guest1892", game.ReplicatedStorage.F1Car)
newcar
was the table returned from the module:
local newcar = Car.new(Vector3.new(1, 0, 1), "Guest1892", game.ReplicatedStorage.F1Car)
^
return newcar
So when newcar:Boost()
is called it’s referencing the newcar
table.
Does this have anything to do with the __index metamethod?
Using a colon is just syntactic sugar. If we have the following code:
local car = Car.new(Vector3.new(1, 0, 1), "Guest", game.ReplicatedStorage.Car)
car:Boost()
The car:Boost()
line is actually equivalent to car.Boost(car)
. This may seem confusing however the function declaration also has the same syntax sugar.
Defining
function Car:Boost()
self.Speed = self.Speed + 5
end
Is actually the same as writing
function Car.Boost(self)
self.Speed = self.Speed + 5
end
So in this case we are actually calling Car.Boost(self)
with car.Boost(car)
. This is how self magically appears and how modifying it modifies the car data. As this is such a common thing to do in Lua we can use colon as a short handed way of doing this.
Yes, because you’re setting the newtable
metatable to the module (that has the __index
method). __index
runs if you call something that doesn’t exist in the original table, in which it will return something else. In this case, the rest of the module:
module.__index = module -- as you can see, this returns the module
Oh so self refers to the actual
Car = {}
itself?
Edit: sorry I’m just not getting it 100% as to how the metamethod is related to self and why it is set to car
Technically you don’t even need self.
self is just used because many people like to write code like the picture up above. It makes the code look more clean. It simply is a way to refer to the object itself.
When writing for OOP I like to think the code you write is a part of the object i. self is simply a keyword for accessing the object.
self is used cause it makes writing code way easier if u use colons in your new function its pretty much not available and u would have to put it in the brackets.
Here is an example that I gave yesterday:
local mt = {
__index = {
changeType = function(self, s)
self.Species = s
end;
changeName = function(self, n)
self.Name = n
end
}
}
local function createObject(name, species)
-- self is just a table with an identity
local self = {
Name = name,
Species = species
}
setmetatable(self, mt)
return self
end
local kermit = createObject("Kermit", "Frog") -- The actual object
local rizo = createObject("Rizo", "Mouse")
print(kermit)
print(rizo)
-- Oh no, Rizo isn't a mouse - he is a Rat!
rizo:changeType("Rat")
print(rizo)
The metamethod .__index is essential here, as it allows our objects to inherit the functions specified in the .__index table. Using Self is not even necessary, however it improves readability. You might find this of benefit.
No not quite. When we call Car.new()
it makes a new table containing data about the car. This new table is called an object in OOP. When we then call methods on this object it is passed to those methods. Perhaps this snippet might clarify a few things.
local Class = {}
-- These two methods are equivalent
function Class.method1(self)
print(self.value)
end
function Class:method2()
print(self.value)
end
-- Let's make some objects
local a = { value = "I'm a!" }
local b = { value = "I'm b!" }
-- Tell Lua to look into Class for the methods
setmetatable(a, { __index = Class })
setmetatable(b, { __index = Class })
-- These are all equivalent too
a.method1(a)
a:method1() -- This is valid even though we define it without the colon
a:method2()
a.method2(a) -- Similar here execept other way around
-- Using b will provide b's data instead
b:method2()
b.method2(b)
-- We can also use the Class methods "statically"
Class.method1(a)
Class.method1({ value = "Who am I?"})
-- We cannot use a colon though as Class doesn't contain our data
Class:method2() -- We cannot provide an object here
Also to clarify, the metamethod stuff is only done so we don’t have to do everything statically. Instead of doing Class.method(object, a, b, ...)
the metamethod stuff lets us do object:method(a, b, ...)
instead. This is the same but just easier to read.
In this case:
Yep nice catch, if you actually tried to run the code it will error (Have you tried it out?)
If so then just add speed to the property.
function Car.new(position, driver, model)
local newcar = {}
setmetatable(newcar, Car)
newcar.Position = position
newcar.Driver = driver
newcar.Model = model
newcar.Speed = 0
return newcar
end
Then if you boost a newcar object it’ll go from 0 speed to 5 speed.
(I know this would be messy, just for the sake of understandment) theoretically if the boost property was inside Car = {} because newcar’s metatable is Car = {} would it still work?
You should try it out yourself. These are the questions you ask the lua compiler and whatever the lua compiler says is Law.
Car = {
Speed = 0
}
Car.__index = Car
function Car.new(position, driver, model)
local newcar = {}
setmetatable(newcar, Car)
newcar.Position = position
newcar.Driver = driver
newcar.Model = model
newcar.Speed = 0
return newcar
end
function Car:Boost()
print(self.Speed)
self.Speed = self.Speed + 5
print(self.Speed)
end
Car:Boost()
local newCar = Car.new()
newCar:Boost()
The output will be
The speed in the Car table goes 0 to 5
The speed in the newcar object created goes 0 to 5
I believe you are confused about the metamethod.
local newCar = Car.new()
--newCar is a property table only containing speed only
--rest is nill cause nothing in parameters ()
newCar:Boost() -- this has a lot of steps
--newCar does not have the boost function
--It borrows from the Car table because metamethod .__index stuff
--Now the newCar table contains the :Boost() function
--This boost function locates the speed property in the current table which is newcar
--increases it from 0 to 5