Fixing Lua OOP

preview_player
Показать описание
An alternative look at the common OOP pattern in Lua programming.

0:00 Intro
0:44 Person Class
1:15 Sending an OOP instance over the wire
4:37 Hot Take
5:14 The Fix
6:53 Types & Ditching Constructor
8:10 Other Thoughts
10:03 Summary
Рекомендации по теме
Комментарии
Автор

Clarification: I am proposing this methodology _instead of_ OOP. I am not saying that this is the "correct" OOP design (it's not).

sleitnick
Автор

you either die a fan of oop or live long enough to see yourself return to functional

itsmeklc
Автор

thank you. ive been an advocate of this for a few years now. the explicit nature makes it easier not only to read but to WRITE as well. no need to make some sort of middleman wrapper to get objects to work across the client/server boundary. works better with typed luau as well, the type system has an easier time when you separate the helper functions from the object type. i still call it 'object oriented' but i make it clear that there is a distinction between this and what the majority of developers are writing.

okeanskiy
Автор

The first time I’ve seen someone feel the same way about metatables as myself, I love it!!!

MonzterDEV
Автор

This take isn't wrong can respect not binding stuff to a metatable as long as there's strong typing to back it. What often makes this pattern convenient for me is that it allows for shorthand member function calls through `self`. I prefer an observer model where state can be reconstructed from a view shared by the server and client, rather than assuming tables being passed over the wire are safe and validated. I also see metatable binding as a contract that says the data was constructed and validated by a direct source. I guess I can see where it could be seen as redundant given how nice Luau's typechecker is now. Sometimes I just prefer `object:SomeMethod()` instead of

MaximumADHD
Автор

This is great. I've been exporting types for a couple of months after learning more about it, because it just doesn't really make sense for games to complicate their data with metatables. It just makes everything so much more readable and easier to work with, and I think this method is underrated.

umamidayo
Автор

Good video, sleitnick! Moving away from metatable usage or otherwise removing access to methods from the object certainly has its benefits, though I mainly see this as a workaround for bad tooling. Luau really should be able to "just handle" idiomatic Lua OOP patterns, including inheritance patterns. That, and there's really no robust serialization libraries available in the Roblox ecosystem - the best we have out of the box is just...well, JSON serialization, as mentioned.

How this pattern could work with inheritance would be a good topic for a follow-up video, I think!

Also, I propose the term POLT: plain-old Lua table - in the same spirit as POJO from Java. Just to move away form struct terminology as it is used in C/C#.

Ozzypig
Автор

At the end of the day, Lua(u) doesn't have built in classes so what we see used is just a popular OOP idiom that allows us to mimic that behaviour and assign functions to our objects. Like you alluded to towards the end, your approach is just plain old tables with some typing to add some structure around their use and then utility tables with functions that mutate the passed in tables data.

Personally, I like to keep the environment and native libs in mind when developing within an ecosystem. Roblox uses the classic OOP idiom of having a class table with a constructor and destructor method and objects have state and logic associated with them so I like the idea of mimmicing that and mainting consistency. As others have mentioned in the comments, I also prefer being able to call methods on 'self'.

There's nothing wrong with different approaches though, everything has its ups and downs and like you say, you can pass these tables over the network without losing any metatable association because you're not using any metatables.

lockefair
Автор

Personally, I think of this method as the purest form of object oriented programming

friedavi
Автор

quite an elegant way of fixing the oop issue

clipnoir
Автор

The LocalScript change you make at 6:30, will work exactly as expected with your original metatable-equipped Person class that used self inside Person:GetFullName() :-) It seems to be that what you're advocating for here is using the single-dot syntax on either side of remote object passing, for consistency. Valid, but you lose class functionality like being able to have a class with operators (e.g. a custom math type with +, *, < etc.). For that, you need your original hack of re-assigning the metatable.

emilybendsspace
Автор

I am not sure I am 100% sold on the idea, but still a big thumbs up for the video. Has certainly given a lot of food for thought.

not sure why this video has taken so long to fall into my feed lol but hey better late than never i guess😅

mr_griffolukegriffiths
Автор

ah yes more knowledge to devour from one of the masters

solderet_wav
Автор

I like this solution a lot and I think it is very convenient for when you're trying to pass data over the network. However, I also feel this idea just won't work in all situations as the larger a class is the more inconvenient this seems to use.

LeehamsonTheThird
Автор

Reminds me of struct's in C with functions you pass it into to change or read the state of the struct. It removes a lot of abstraction of hiding the methods with the data and instead focuses on the data inside the object instead of the object itself by making the methods modular. For most things this is appropriate, because most things don't involve complex data structures with specific requirements and unique actions that require a level of abstraction beyond the initial state. But even for that you can generally avoid metatable magic with closures and it basically does the same thing. Although I haven't worked with closures much in lua, so I'm unsure if there's any limitations to be aware of, but I know they're there and they work.

jamesmann
Автор

What about having events in your proposed solution, like Person.NameChanged? Do you think a different approach should be used for events? I'm interested in hearing your thoughts on that.

homelessdorito
Автор

I’ve come to this conclusion as well. It lowers code complexity and as seen in the video is compatible with serialization. Great vid!

Jaysinxe_
Автор

The only counter I have to this is, some patterning makes for very clear logic switching and explicit filtering.
There is something to be said in the ease of it, but in my experience that ease leads to bad habits.

Why not build a top level class of all your classes with a built in flatten class functionality, that can be overwritten to customize for that class? That can just easily be reconstituted.

My biggest issue I've seen is that more often then not, devs don't have a root class that all other classes should be inheriting from. So that you can homonogize behavior better. <shrug> just thoughts

blendedphoenix
Автор

Before I learned about metatables and wrote Love2D games, this is how I did "objects" in Lua

Fezezen
Автор

Me personally, i wouldn't use it for two reasons:
1. I like LUAU OOP the way it is, and the way everyone uses it, because it simplifies life a lot.
2. Replicating tables WITH FUNCTIONS, hell naah, i'll never replicate tables in my life. I'd rather do proper replication with the maximum of serialization that i can do.

pestik.