Is this the right category? I was debating scripting support, code review, or dev discussion
PLEASE NOTE: This topic is NOT about the differences of how colon vs dot works. I already know that functions with a colon automatically have self inserted as the first parameter.
Often times when declaring functions in modules, I use the colon instead of dot, even when I dont need to use self. It just looks a lot nicer imo, and is more consistent with built in functions like :GetAttribute, :FindFirstChild, etc.
Examples:
function mapLoading:LoadArea(areaName: string, state: boolean): ()
-- whatever
end
function dataUtility:GetProfile(): ProfileReplica
-- get the profile here
end
function playerUtility:ResetCameraPosition(): ()
-- set camera cframe here
end
Is this actually a good reason to do this though? Is there any real performance drawback to using colons vs dots?
Personally I would find this confusing as you don’t know if the module is an object or not and needs to be instanced/created first with Object.new().
Performance wise you should measure it yourself using os.clock() probably won’t be more than a 0.0001 ms difference
local module = {}
function module.Dot()
return
end
function module:Colon()
return
end
return module
-- in normal script
local mod = require(script.Parent)
do
local start = os.clock()
for i = 1, 10000 do
mod.Dot()
end
print("Dot: "..os.clock() - start)
end
do
local start = os.clock()
for i = 1, 10000 do
mod:Colon()
end
print("Colon: "..os.clock() - start)
end
It’s fine to use either. They both produce the same outcome. I think it all just comes down to personal preference. As @dthecoolest stated, I think it just aligns more with how Roblox creates instances / objects when you use both:
Instance.new() -- Notice dot notation is used instead of colon
Methods are often what use the colon notation and they are functions that are are members of an object but you can still use the dot notation on the same function to produce the same outcome:
-- These both produce the same outcome
Instance:Destroy() -- Using colon notation
Instance.Destroy(Instance) -- Using dot notation
Like I said, it just comes down to personal preference. I really only use dot notation when creating an object and colon for functions within that object. Performance wise it shouldn’t really matter - the difference is not big enough to cause issues. You’d just be micro-optimizing at that point.
I would recommend against doing this. Consistency is a big deal within programming and using colons for non-classes makes things messy. Use dot notation for non-classes and colons for classes. No exceptions.
I second this, it is just unconventional to use colon for regular function calls.
I argue the opposite: Using colons the way you’re trying to use it gives people the false assumption that they are working with objects, when in reality they’re not and it’s just a regular module with different functions.
In the Roblox API, colons are only used for object methods, and dots are used for statics that pertain to the class itself.
It would be true in the case of module:Whatever(), but if ran with module.Whatever(), it would be nil.
Same goes with
local module = {}
local something = 'egg'
function module:Whatever(somethingElse)
print(something == somethingElse)
end
return module
It will expect you to always use module:Whatever('egg'), because if you use module.Whatever('egg'), it will register as if somethingElse is nil and self is 'egg'.
Throwing my two cents in here. Regardless of the fact that this is Lua (&\Luau) syntactic sugar, it doesn’t mean “use whatever you want”. It should really mean “refer to your style guide”, and in the instance of most large Roblox projects this means referring to the Roblox Luau style guide (which is how Roblox writes its instances, including within locked standard lib metatables [Vector, CFrame, etc…]).
Scrolling down a bit, you will find some basic OOP rules.
Constructors are written as .new.
Methods that don’t directly operate on your object are wrote in dot notation.
Methods that do directly operate on your object are wrote in colon notation (most methods).
self persists regardless, it is only syntactic sugar. The produced bytecode is identical, if you’re curious enough you can pull a compiler and see. The real argument here is how unidiomatic the code becomes when dot gets used for everything. The only time the “performance” difference matters is when the Luau virtual machine retrieves the object. If the object is global in scope it only needs to get pulled once with colon notation, whereas with dot notation it gets pulled twice. Basically, : will never be slower than .ever because colon acts to perform actions only once internally.
you should take the averages of many attempts, here’s what I got
local funcs = {};
function funcs.dot()
local start = os.clock();
for i = 0, 999999 do end
return os.clock() - start;
end
function funcs:colon()
local start = os.clock();
for i = 0, 999999 do end
return os.clock() - start;
end
local function compare(n)
local dotSum = 0;
local colonSum = 0;
for i = 1, n do
dotSum += funcs.dot();
colonSum += funcs:colon();
end
local dotAvg = dotSum/n;
local colonAvg = colonSum/n;
print("DotAvg: "..dotAvg);
print("ColonAvg: "..colonAvg);
print("Difference: "..dotAvg-colonAvg)
end
print("\nattempt 1")
compare(1000);
task.wait(1);
print("\nattempt 2")
compare(1000);
task.wait(1);
print("\nattempt 3")
compare(1000);
task.wait(1);
print("\nattempt 4")
compare(1000);
warning this lags the game a lot if you’re gonna test it yourself
So again, you don’t need to benchmark this. The differences are well documented.
The instances where dot performs faster in your example only occur when the Luau VM is pulling once regardless of dot or colon notation and you just happened to receive faster performance (basically, they are exactly identical in your example). You are not working with globally scoped objects and therefor you will never see a performance difference. And even if there was a performance difference, you have implemented it wrong for benchmarking given that you should be passing funcs to itself with dot notation (funcs.dot(funcs) to match self).