No, self would be defined as list
in this case.
Remember,
list:GiveSpeed(Player1, 25)
is the same as
list.GiveSpeed(list, Player1, 25)
No, self would be defined as list
in this case.
Remember,
list:GiveSpeed(Player1, 25)
is the same as
list.GiveSpeed(list, Player1, 25)
Oh, but how would it give the player the speed then?
Also, is it true that if I had this:
local list = {}
local function list:GiveSpeed(....)
--....
end
Is that true to say the function is inside that table?
Because if not, __index could be useful
Youâd probably use Target in this case, youâd redefine target to be a player instead of a model.
function list:GiveSpeed(Target:Player, Speed:number)
local character = target.Character or target.CharacterAdded:Wait()
character:WaitForChild('Humanoid').WalkSpeed = Speed
end
Yes, itâs in that table. You can use metatables here though, it would be useful if youâre working with many tables (eg. one table per player) but Iâm not sure if youâre doing that.
local metamethods = {}
metamethods.__index = metamethods
function metamethods:GiveSpeed()
-- ...
end
function metamethods.new()
local obj = {}
-- properties/events inside of obj here
return setmetatable(obj, metamethods)
end
return metamethods
You canât define local functions inside of a table though, you need to define it as function table:func()
, canât do local function table:func()
, youâll get an error.
local module = require(path.to.module)
local newObj = module.new()
newObj:GiveSpeed() -- in this case, `self` would be newObj
Yeah, those custom- functions I understand,
But what makes those different from using metatables
Because I heard some people say there is a huge difference
And this makes it look like itâs easier to make âcustomâ functions
Oh.
I did that because I am used to use local variables because they are better than global ones
Thats exactly where I am trying to figure out what is that.
What properties do I put inside obj?
âWalkSpeedâ? âHealthâ? â.Changedâ?
Metatables are often more helpful when it comes to object oriented programming or doing arithmetics on tables (like adding/subtractingâŚ) because it allows multiple objects of the same class to exist while only referencing a single function which is useful when it comes to being conservative with memory, really it all comes back to memory.
Metatables are also useful for proxy tables, object wrappers (which I mentioned previously), locking properties among many others.
Thereâs a big difference between a library and an object. In this post, youâre creating a library to manipulate an object. Libraries and objects both are useful in their own ways. Libraries may contain objects but often theyâre done for utility and utility only. Libraries are useful when it comes to having complex functions that are related in some way. For example, string and math are both libraries but they both do not contain any object creation. I guess, looking at it, libraries usually work with constant values. A library will have many values inside of them that never change. For example, math.floor is a function obviously, and this value will never change. Likewise, math.pi is a constant number that exists so you donât have to type out 3.1415926⌠every time you need to do something that relates to a circle.
I guess the biggest takeaway is that libraries contain objects and values that never change. Theyâre also useful so you donât have to rewrite the same function over and over which again is unwise for memory reasons.
The difference between a library and an object is that an object will have variable properties, and usually objects represent something. For example, a part is an object. Every part has its own individual properties, every part is standalone, this goes with any object.
The reason metatables are useful for OOP is for memory reasons (which I keep reiterating on, sorry lmao). Every class should have its own set of functions, however these functions are not per-object, they are a single constant table that exists between every object. 100 objects, 1 table of functions.
For example, if we attempt to compare two instancesâ âdestroyâ functions, they will be the same, despite the two instances not being equal to each other. Think of the class functions to be like a library.
local p1 = Instance.new('Part')
local p2 = Instance.new('Part')
print(p1 == p2) -- false, they are two different objects
print(p1.Destroy == p2.Destroy) -- true, although these are two different objects, they share the same "Destroy" function
Thatâs up to you. If you want to set these properties, you can do something like:
function object.new()
local newObj = {}
newObj.WalkSpeed = 16
newObj.Health = 100
newObj.Changed = signal.new() -- I'd recommend using a custom signal object since bindable events are inefficient but it's up to you
return setmetatable(newObj, object)
end
However, it isnât possible to detect any changes inside the table currently, youâd have to use a proxy table which is another concept that also relies on metatables but yeah.
Makes sense, no doubt.
So those functions belong to library since they are constant and do the same thing among different objects.(destroy works for both gui and baseparts for example).
On phone right now so it is a bit difficult to quote what needs to be quoted,but -
About the last, the properties:
local metamethods = {}
metamethods.__index = metamethods
function metamethods:GiveSpeed(target:Model)
target.Humanoid.WalkSpeed = self.WalkSpeed
end
function metamethods.new()
local obj = {}
obj.WalkSpeed = 16
obj.Health= 100
-- properties/events inside of obj here
return setmetatable(obj, metamethods)
end
return metamethods
And on a diff script:
local module = require(blah blah..)
game.Players.PlayerAdded:Connect(function(Player)
if Player.Name = "Valkyrop" then
local char = Player.Character or Player.CharacterAdded:Wait()
if char then
module:GiveSpeed(char)
end
end
end)
Also did I do it correct here:
function metamethods:GiveSpeed(target:Model)
target.Humanoid.WalkSpeed = self.WalkSpeed
end
Sort of, yeah, they exist to conserve memory. They arenât really libraries though, theyâre usually referred to as class functions, class methods, class members etcâŚ, the class being the thing that your object represents.
signal
would be a custom signal object/âeventâ. Robloxâs signal is called âRBXScriptSignalâ, it represents every single event in every type of instance. A signal is also an object. For example workspace.DescendantAdded is a signal.
It could also be a BindableEventâs âEventâ signal which is what most people that arenât using a custom signal class use.
So in your example, an object isnât really useful since youâre passing the target model anyway. OOP and metatables arenât really useful here. Youâre probably looking to create a owner/permissions/character module (library) that contains all of the relevant character utility functions.
So,
local permissionModule = {}
function permissionModule:GiveSpeed(target: Model, speed: Number)
target:WaitForChild('Humanoid').WalkSpeed = speed
end
return permissionModule
Then you could call the function:
local module = require(path.to.module)
players.PlayerAdded:Connect(function(player)
if player.Name == "Valkyrop" then
local character = player.Character or player.CharacterAdded:Wait()
-- you don't have to check if character exists here because we're yielding until it does exist (prev. line)
module:GiveSpeed(char, 25)
end
end)
Oh if youâre looking to do that then yes, since self
would be equal to module. Just ensure thereâs some number inside of module
whose index is WalkSpeed.
local module = {}
module.WalkSpeed = 25
function module:GiveSpeed(target: Model)
target.Humanoid.WalkSpeed = self.WalkSpeed
end
Oh, but I thought that the setmetatable thing below connected and made it so that WalkSpeed is inside our table here, hence self is metamethods table and WalkSpeed exists there
local metamethods = {}
metamethods.__index = metamethods
function metamethods:GiveSpeed(target:Model)
target.Humanoid.WalkSpeed = self.WalkSpeed
end
function metamethods.new()
local obj = {}
obj.WalkSpeed = 16
obj.Health= 100
-- properties/events inside of obj here
return setmetatable(obj, metamethods)
end
return metamethods
In that case, self
would be equal to the new object, yeah. But you would have to go through your constructor to call the function.
local module = require()
players.PlayerAdded:Connnect(function(player)
module.new():GiveSpeed(player.Character or player.CharacterAdded:Wait())
end)
Sheesh, I think things begin to be more clear to me now. Still not 100%, but better than last time lol.
Tho, what does the ânewâ function does? Is it important when working with oop?
Is it just a normal function like others?
ânewâ is just a generic name for an object constructor. For example, Vector3.new() and Instance.new(), those both return objects but theyâre just normal functions.
Yeah, ânewâ is just a commonly used name. You could really call it whatever you want, I think ânewâ is used because thatâs what other languages use (eg. let a = new Object()
) but it literally does what it says, creates a new object.
Oh thatâs really nice.
I will soon make a small module with custom events lol, and Iâd like to know what you think of it( sort of implemention of what have taught me). And again,
Appreicate the patience and time!
So basically, to create more events I just make more functions and add desired properties to the same obj table inside the ânewâ function?
Thatâs right, Iâll just do a brief summary of what an objectâs module could look like:
local object = {} -- this table will be referred to as 'object'.
object.__index = object -- 'object' should contain metamethods
-- optionally, if you have constant properties you can also define them in object, but these should only be values that are **never** changed
object.ClassName = "CoolObject"
function object:DoSomething() -- 'object' should also contain class functions
print('hi')
end
-- this function is the function that creates our new object, the constructor:
function object.new() -- remember this is just a normal function with the name "new"
local newObject = {} -- this table is our new object, think of it as a canvas that we can do whatever we want with
--^ will refer to this table as newObject
newObject.Cool = true -- newObject should contain our properties that may vary (static/constant properties can be added here as well but that's up to you)
return setmetatable(newObject, object) -- newObject's metatable is now the "object" table from above
end
return object -- return the table that contains all of our object properties
Understood everything except this.
I know that ClassName is the indez and CoolObject is the value inside the table.
But:
Howâd that affect on our functions?
Wont our table now have functions and properties? Confusing a bit
Accessing it prob gonna be self.ClassName
Thatâs just for a property that will never change. Remember how libraries contain values that will never change? Same thing pretty much.
Hi, so I have this:
local metamethods = {}
metamethods.__index = metamethods
function metamethods:GiveSpeed(target:Model)
target.Humanoid.WalkSpeed = self.WalkSpeed
end
function metamethods.new()
local obj = {}
obj.WalkSpeed = 16
obj.Health= 100
-- properties/events inside of obj here
return setmetatable(obj, metamethods)
end
return metamethods
local humanoid= require().new()
players.PlayerAdded:Connnect(function(player)
humanoid:GiveSpeed(player.Character or player.CharacterAdded:Wait())
end)
Howâd I make it so that, if I were to make this event - Add(stat:string , value:number)
, itâd look for a descendant value named that inside the player and add that value[ and not setting it,like with the walkspeed]
Is this okay?
local metamethods = {}
metamethods.__index = metamethods
function metamethods:GiveSpeed(target:Model)
target.Humanoid.WalkSpeed = self.WalkSpeed
end
function metamethods:AddStat(Target:instance,Stat:string, Value:number)
for _,data in pairs(Target:GetDescendants()) do
if data.Name == Stat.Name then
data.Value += Value
end
end
end
function metamethods.new()
local obj = {}
obj.WalkSpeed = 16
obj.Health= 100
local value = instance.new("NumberValue")
--What here
return setmetatable(obj, metamethods)
end
return metamethods