Making a game nearly fully OOP

Modules have the benefit of allowing you to control when they are executed since they only run when using require, so for single use objects they are a good alternative than creating a class

It’s important to remember that modules cache (store in memory) the value that they return, so if you require the module again the same object created when first required will be returned (replication rules apply, LocalScripts will receive a different object than server Scripts will)

1 Like

I think you would want to use a single dot instead of “:” though? But im not sure.

local System = {}

function System.Init()
    -- Initialize system
end

function System.SomeMethod()

end

return System -- (or return System:Init())

I think that’s just preference, I think the “:” looks nicer.

The two options you show are both viable patterns, serving different use cases.

This first example assumes that you’re intending to create multiple instances of System objects, where each object is a table which is an instance of the System class, and has inherited all of its functions via the metatable and __index mechanism. This also allows for inheritance, since you can create anothe ModuleScript whose new() function first constructs a System instance, and then adds or replaces methods or properties (base class functionality is accessible through the __index mechanism and metatable. If you return System.new(), this is just enforcing a singleton, since the return value of a ModuleScript is cached the first time it is required in any VM context, and all subsequent requires of the same ModuleScript will get the same instance.

Your second example is also enforcing a singleton, because its not creating a class template at all, it’s just creating a single table that is being treated as an object (an instance). There’s no constructor, and no way to make multiple instances of it (well, technically you could with require(ModuleScript:Clone()), but definitely don’t do this!)

With this second example, you can’t do return System:Init(), unless the Init() function returns something, otherwise require doesn’t return anything. Even if you had:

function System:Init()
    return self
end

There is still no point to return System:Init(), because it’s returning the same thing as return System, and you might as well just not have the Init() function at all and just inline the code, since it’s going to run only once with the first require either way.

2 Likes

Alright, that clears up a lot, thank you! I will probably go with the second option, as adding __index and new and all of that just to make it a singleton seems like extra stuff that isnt necessary.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.