I haven’t tried OOP with Lua yet, since most of my projects use a singleton format. So I’d have to ask: since OOP is becoming increasingly part and parcel to the Rōblox development scene, has someone yet written a library that simplifies class implementations?
My thoughts are that it could extend on the principle TypeScript uses to simplify constructors:
There are many libraries available however I’d advise you to consider the consequences of using a library before just diving in.
What I consider to be the main strength with this way of doing OOP in Lua is that is has no external dependencies. Once you have external dependencies you have to drag them around wherever your scripts go, you are locked into their way of doing things and it is more difficult to refactor later. This is not necessarily a bad thing if you don’t mind that, but it is important to consider. Make sure, if you accept these disadvantages, that the advantages are comparatively worth it.
Now there are a large range of libraries/tools available, from tiny little ones which just give you slightly cleaner syntax, large ones which automatically give you cool features such as reflection information and huge ones which completely transform the language!
One such library/tool which you might be interested in due to your mention of TypeScript is roblox-ts which effectively lets you use TypeScript in Roblox. It is still in development so it is advised to only use it for experimentation however it is quite amazing.
That’s why I couldn’t consider using larger dependencies (such as Roact) yet. One that creates a shortcut for initialising classes wouldn’t require a drastically new way of doing a major process. In fact, I had used to include a huge library of functions I made that took so long to prepare that it would time out before the actual script run.
There doesn’t seem to be an answer so I’ll post it:
Connections to object methods
I haven’t found an elegant way of handling this since the parameters passed by the connection are not related to the object itself, the simplest way I’ve come up with is to have an object method that returns a function, which is then connected to, like so:
function Obj:eat()
return function()
print("eated")
end
end
local a = Obj.new()
a.Value.Changed:connect(a:eat())
local function bind(method, obj)
return function(...)
return method(obj, ...)
end
end
function Obj:eat()
print("eated")
end
local a = Obj.new()
a.Value.Changed:connect(bind(Obj.eat, a))
Wow, at first I was intimidated by OOP with all the metatables and everything. But then, after reading your thread, it cleared up some of my questions about it. Now, I truly see how this is super useful. I can’t wait to use it!
Thank you so much for taking your time to write this, it helps a lot!
THANK YOU
Thank you, this was very helpful. I already knew OOP from Java, though by just reading some scripts utilizing it I didn’t understand it. You were my rescue. Thanks, man.
This is super well explained however I don’t understand what do the 5th line in the last block of code. I tough the syntax was setmetatable(<table>, <metamethod>)
Private properties are only applicable to inheritance, and would be overkill in Lua.
Trust me, I’m the king of overkill. Eight years ago I made some pretty sophisticated OOP logic for Lua, and it was quite a challenge to figure out the best implementation.
If you’re looking for a certain item in a table and it does not exist, __index will “fire” and redirect it to the proper area (I think?). Anyways, why do you do
Car.__index = Car
Basically, whats the point of setting Car’s __index to Car again? Wouldn’t that theoretically just start an endless loop with the Car table?
Keep in mind the distinction between a metatable and a table. You can think of a metatable as a list of events for a table. The car table is the metatable, not the table being indexed. So if we have a car object we set it’s metatable to Car with setmetatable({}, Car). This means when we do a function call it looks into, in this case, an empty table so fires the __index metamethod which redirects it to Car. Conveniently Car is where we defined all of our functions! This is nice as it means we only need one copy of the functions, instead of putting them inside every object.
The circular case you are imagining would be setmetatable(Car, Car).
local NpcModule = {}
NpcModule.__index = NpcModule
function NpcModule.New(Name, Job, Age)
local NewNpc = {}
setmetatable(NewNpc, NpcModule)
NewNpc.Name = Name
NewNpc.Job = Job
NewNpc.Age = Age
return NewNpc
end
Npc = {}
for i = 1, 5 do
Npc[i] = NpcModule.New(RandomName, RandomJob, RandomAge)
end
return NpcModule
I’m trying to do a Database, did you have any idea how I store Npcs data?
You article does a great job of explaining how to achieve encapsulation with Lua.
Do you happen to have a sample project with that code. Would love to have a working example to play around with.
I see some other links in that post describing that Lua can may also achieve object composition/inheritance. Any good working examples of that as well ?
I’m guessing Lua probably does not support polymorphism.