Why do so many people do MyOwnService:Method instead of MyOwnService.Function

Isn’t it redundant to pass the service as a parameter since the methods are never used anywhere else?

3 Likes

Instances should listen to __call and so if you prefer you can do the following:

MyOwnService("Method", ...)

like:

workspace("FindFirstChild", "BasePlate")
1 Like

They listen to namecall not __call I thought and namecall can change anytime so thats bad
Also I mean Services not inherited objects
And I mean not only Roblox but other people too

But a good roblox example is

I assume you’re referring to user-implemented Lua oop since you mention “MyOwnService”. I’ll try to address both types though.

OOP usually centers around classes and instances, in which a class is a blueprint and an instance is an object made of the blueprint of given class. That’s the right way of doing OOP anyways not just spamming colons and hoping for the best.

Anyhow, when you call a function (i.e use dot syntax) in OOP speak you’re calling a static function. That is, it is not bound to any given class instance, it’s just part of the class itself. The colon syntax signifies it’s a class method, and a self/this argument is required because it uses information from its instance. An example is :GetChildren where self is the instance and must be known because it’s specifically the children of we’re asking for.

The implementation of sharing the same exact function for every instance that uses it and instead just passing the extra self/this param makes it so each instance doesn’t need its own specific copy and such, which would be memory and performance devastating.

As for the concern of when the colon syntax is irrelevant, I’d say a function is static when the self/this parameter is not used for anything. However, the example MarketplaceService may internally hold data Roblox uses and such, and said data might be used by the method. So instead of making all its properties static and possibly making the codebase harder to deal with, it’s easier to make use of the OOP approach.

The same applies for user code. Although singletons shouldn’t really have their specific methods be non-static in an ideal world, they are for the sake of possibly consistency and simplicity.

11 Likes

Can you elaborate on when these two don’t overlap?

1 Like

I’m not sure what you mean by overlap. Both are OOP concepts. The difference between singletons and a normal instance is that there ideally is only ever one instance of a singleton class active/created at any given time.

The other approach would be a static class, which would allow for using its static methods and it internally keeping its state without ever using a self/this argument.

There are some reasons to not use that approach at singletons, though. For one, Roblox instancing depends on the actual instance being there, and a static blueprint might not work too well as a replacement. Things like place teleportation might also be problematic, since the datamodel tree is flushed and a new one is created, which means it’ll have different settings and such you’d have to manually specify to update to the specific classes, as opposed to just freeing the object memory and creating a new one.

6 Likes

Dang teleporting is an awesome example

Can we make the following assumption (for the sake of proper definitions):
If something can be destroyed without the game restarting/closing then it is an instance

So with that definition Roblox services would be instances

But what about user created “services” such as a lot of the modules in CrazyMan32’s framework:

A specific example could be:
https://github.com/Sleitnick/AeroGameFramework/blob/master/src/ServerScriptService/Aero/AeroServer.script.lua

Edit: for your first paragraph I meant when is it not colon spam and is instead done for consistency?

I use : for class/service methods because it is consistent with Roblox API. I only use . for constructors (.new()) and library (utility) functions for the same reason.

7 Likes

An example of colon spam would just be making a table to collect functions in with no self usage and then having it all use : to call.

Consistency is having an instance and it being more convenient to have all methods/functions use : if most already do.

Also, yes, Roblox services are instances. Afaik all instances inherit from the base class Instance, in that sense they are. Ignoring the base class, the fact that they are instantiated from a class means they are an instance in a more general programming meaning.

User created services are usually wrapped tables, userdata, etc. I’d say the same about them as I would Roblox instances for the most part, with the only real differences being the higher level implementation.

2 Likes

I mean they are more like objects than classes

So for the example https://github.com/Sleitnick/AeroGameFramework/blob/master/src/ServerScriptService/Aero/AeroServer.script.lua
would you consider using colon to call appropriate?

The example seems like fine OOP.
Also, classes and objects are not exactly handled like that.

A class is more of a blueprint. Imagine C++ classes.
When you define class Something you aren’t actually creating any new info in the program’s memory (unless it’s virtual inheritance but let’s forget about that for the sake of this specific topic). When you then write Something myClass, the compiler looks up the blueprint (Something) and structures the new object accordingly. The blueprint is only ever available during compile-time, and it tells the compiler how to structure instances of the class.

Obviously we don’t have this ability in Lua, so metatables are used instead for user-defined “classes”. Singletons are instances of the blueprint that the Roblox codebase defines them to be. Their only real quirk is that there is only supposed to be 1 active instance of that class. Using instances as opposed to a static class (which is essentially a reserved piece of memory that remains in the same structure during the entire flow of the program) is both ease of access for Lua (no special cases) and ease of control on the Roblox end (if it’s ever needed to reset the properties you don’t need a dedicated function, just deallocate the instance and create a new one).

1 Like

I think it’s worthy mentioning some services aren’t even instantied on every place, for example, Teams and TestService:

image

Because services also inherit Instance, properties like Name are also encoded, for example, when a place is uploaded.

self is never used where AeroServer can’t be though

Also I guess I mean singletons not classes

Ah nevermind, only quickly glanced over it. Not really object-oriented, and yes those functions could all be made static instead, which would probably work better for things like passing them to other functions without also having to pass the object and such.

1 Like

I don’t understand what you mean

When you define a function in this format:

function abc:xyz(n1, n2)
    return n1 < n2
end

It actually compiles to

function abc.xyz(self, n1, n2)
    return n1 < n2
end

However take things like table.sort which can take a function.
If you pass it this way, it’ll error.
table.sort(blah, abc.xyz) because xyz is called as xyz(arg1, arg2, nil).
In which case, self is arg1, n1 is arg2, and n2 is nil.

When you define the function normally using . syntax, though…

function abc.xyz(n1, n2)
    return n1 < n2
end

You get the expected result.
Basically, option 1 you can’t pass around the function and expect it to work normally unless you also have a special case to pass the object (self) with it.

3 Likes

A static method belongs to the class rather than object of a class. A static method invoked without the need for creating an instance of a class

Consider the code below:

local Car = {}
Car.__index = Car

function Car:GetSpeed()
    print(self.Speed)
    return self.selfSpeed
end

function Car.new()
   local newCar = {speed=10}
   setmetatable(newCar, Car)
   return newCar
end

--somewhere else
local myCar = Car.new()
local gotSpeed = myCar:Test()

Would Car:GetSpeed() be a static method because it’s under the Class table rather than the object/instance table, even if it’s using self. How about if it was not using self at all?

If the method does not use self, it’s a static function in Lua terms. Regardless of if the method is on the class and accessed by metatable or directly in the instance, if it does not use self then it is static and should be written as such.

1 Like

Thank you so much for clearing that up!

--constants
local PLAYER = game.Players.LocalPlayer
local PLAYERGUI = PLAYER:WaitForChild("PlayerGui")
local MAIN = PLAYERGUI:WaitForChild("Main")

local Gui = {}

function Gui:ShowWepInfo()
	MAIN.WepInfo.Visible = true
end

function Gui:HideWepInfo()
	MAIN.WepInfo.Visible = false
end

function Gui:UpdateWepInfo(wep)
	if wep.weptype == "Firearm" then
		MAIN.WepInfo.Pool.Text=wep.pool
		MAIN.WepInfo.Mag.Text=wep.mag
	else
		MAIN.WepInfo.Pool.Text="-"
		MAIN.WepInfo.Mag.Text="-"
	end
end

return Gui

This is my GUI module. I’m assuming all of these methods are static?

Seems like the Gui table doesn’t actually store/use any data and the functions use upvalues instead, so yes.

1 Like