Let’s suppose I have a module script that manages players’ camera functionalities. I’ve heard on some posts that methods are less efficient than normal functions:
local camera = {}
camera.__index = camera
function camera.New(Character)
local self = {}
self.Character = Character
self.Humanoid = Character:WaitForChild("Humanoid")
return setmetatable(self, camera)
end
function camera:Booble()
local hum = self.Humanoid
-- Booble system using Humanoid from self.Humanoid
end
return camera
local camera = {}
function camera.Booble(Humanoid) -- Or store Humanoid in the module script as a variable
-- Booble system using Humanoid from the parameter
end
return camera
Are methods really bad? And if it is, when should I refrain from using them? Regarding the first example script I sent, is it necessary to store Character into an OOP to use it further in the script, or use the second example script?
Regarding OOP, there will always be performance trade-offs. OOP is known for not being… well optimised, but it’s very helpful.
In terms of a method, there will be a fair bit of overhead; Luau first searches the table, then gets the metatable, sees if __index is set, sees it is, and then searches that table, finds the key, and returns it.
Having a normal function will induce less overhead because the function has known placement, and doesn’t need to be searched for as much. So Luau just grabs it, and off it goes.
In both parts, parameters will induce the same amount of overhead, because they get pushed to the stack with the function.
Manually storing a function, like @Yarik_superpro said, will be faster overall because Luau does not search for the function when it is called, each time it is called, rather it is searched for at the start and referenced by an upvalue, inducing less overhead.
Overall, OOP methods will be less efficient because of the additional search and call overhead.
Other than performance, OOP is designed to manage a class structure, which makes it easier to control multiple objects that essentially have the same functions and behaviors, such as guns, cars, or even pets. Therefore, there is no benefits in using OOP for a single object such as the camera.
Expanding on this; why are you creating a class for something such as your camera? If you’re planning to instantiate it as a singleton, there’s only a point in doing that if you have extra data and methods you need to be centralised and shared which cannot be shared by other means. Is this the case?
If not, consider a normal module, as you can provide centralised functions without as much index overhead or a wrapper.
I have been wondering that too.
I suppose this issue comes with education building the wrong mindset in beginners or it being their attempts to fill gaps in knowledge.
That’s the same thing as when they are using “Init” or such a method in class creation instead of it being integrated into the constructor.
That being the main reason why I feel disgusted to use OOP in general.
I don’t think it’s an education issue, but rather an attempt to ‘flex’ their scripting skills by overcomplicating scripts and believing it makes them look more professional. Many scripters aspire to learn and use OOP because it is primarily used by highly experienced developers, then think that using OOP mean your’re a good scripter. So once they learn it, they tend to use it everywhere, even when it might not be necessary.
I have seen in my ads a lot of “OOP” slop courses pop up, and I think it’s the main source of disease. People are taught that OOP is so perfect and such that they get completely zombified into using it everywhere, even in stupid nonsense cases.
Does anyone remember the knit epidemic?
local module = require(path._M)
local print = module.Print
local doSomething = module.DoSomething
local doAnotherThing = module.DoAnotherThing
local whatever = module.Whatever
OOP is not always bad. Although it has a costly performance trade-off, it’s a lifesaver for organising complex systems, hence why some languages literally have it built in.
A simple module like _M - I wouldn’t worry about storing it separately, it’s not actually that much overhead for something like that.
OOP - the same, but more overhead. It’s kind of down to microoptimisations at this point.
If you want a golden rule to follow:
Don’t try to use OOP for the sake of it. Only use it where you actually need it.
if you want a little abstraction i guess you can but dunno man.
you can make it even more dead simple:
return {
_M.Print=function()
end;
_M.DoSomething=function()
end
}
Methods and OOP is fine if its not abused the hell out of it and if its well optimized. (i mean why do you need OOP without methods in first place? just referance function dirrectly)
Also make sure to inline functions from module:
local module = require("./MyModule")
local Print,DoSomething = module.Print,DoSomething
--althrough probably avoid this tuple type like referancing probably
you can also implement most of OOP with functional programming instead and it may even be way easier to use…
Singletons in OOP is a joke, just use dirrect functions
I have a module script that handles items that appear on my game. For example, if I want to create a new item, I call for New function to create a new Item object, and then I can do whatever I want with it:
local item = Module.New("Apple", {Health = 30}) -- Example
local name = item:GetName() -- Returns the item's name, in this case "Apple"
local spawn = item:SetSpawn(position) -- Sets the item spawn
local spawnTime = item:SetSpawnTime(60) -- Will appear after 60 seconds
item:StartCountdown() -- Will yield the current thread until item appear with the specified spawnTime
item:Spawn() -- Will spawn the item with the position specified
Is it a good OOP practice, in this case? Or should I refrain to use it still? Because if I didn’t do an OOP for this type of thing, I would probably need to do a lot of functions with parameters and would just look ugly in my opinion.
If you plan to have multiple, then yes. But like @1kaelen1 said, try to use properties - they’ll create less overhead than extra functions to read other data.