In fact, luau has encapsulation (metamethods + typing), you just need to be able to do it. For private fields, there are metamethods __index and __newindex, for public fields, there are attributes (or function arguments). By the way, this is easier to do with the separation of logic:
--!strict
local Class = {}
local ClassMeta = {}
ClassMeta.__index = function(self, key)
if key == "B" then
error("Handle error")
else
return Class[key]
end
end
ClassMeta.__newindex = function(self, key, value)
if key == "B" then
error("Handle error")
else
rawset(self, key, value)
end
end
function Class:GetA()
return self.A
end
function Class:SetA(value: number)
self.A = value
end
local _B = newproxy(true)
function Class:getB(): number
return rawget(self, _B) :: number
end
function Class:setB(number: number): ()
rawset(self, _B, number)
end
type ClassType = {
A: number
} & typeof(Class)
local function new(number: number): ClassType
local self = setmetatable({}, ClassMeta):: ClassType
self.A = number
rawset(self, _B, 2)
return self
end
type Module = {
new: (number: number) -> ClassType
}
return { new = new } :: Module
By the way, this method does not allow you to call __index cyclically, does not allow you to call a constructor from a constructor, does not break the distribution of annotations “.” and “:”
Interesting ressource. If you’re interested, something that’s also very clean and productive is to put things in a same location in a dictionary. I do mostly do this with services, and so you just have to put Services.Players to use the player service. Looks professional, and spares you from an extra “local”!
It’s also an extremely simple way to have a good DRY level. Putting your services in a table often reminds me to create a variable where all my modules are located e. g.
please dont do this, just call your services manually with different variables
if you actually want to do something like this, I’d make a module for it, but it’s recommended to create a new variable with GetService at the top of the script for every service
RS is a much more commonly used service compared to the only other service that could be abbreviated with RS, which is RunService
It’s used in videos on youtube, posts on devforum and comments on discord, really anywhere, bc its abbreviation is ubiquitous and is known to be associated with ReplicatedStorage. If I see RS in code, I know it’s replicated storage and so do others. So, it doesn’t reduce any self-documentation since anyone who’s been scripting enough on Roblox should know that RS = ReplicatedStorage.
It’s one of the more special abbreviations bc so many ppl use it, maybe the only one.
If you have a variable that u wanna call RS, call it something more meaningful then bc it’s pretty safe to say that it’s not more important than ReplicatedStorage for it to be taking its well known “RS” name.
I agree with most of the points made here but personally I think that a casing style like snake_case or PascalCase would be better for readability. For me when I’m reading code that primarily uses camelCase I tend to skip over the first word or the entire variable like 80% of the time which can cause some amount of confusion, but with snake_case each word is very clearly separated and imo much easier to read. Overall though good advice
According to the naming convention, you should not abbreviate class names. And even more so those classes that need to be allocated (services/singletons)
Abbreviating variables makes it generally harder to understand your code and you gain next to nothing from doing it. Its a lot easier to understand code with variables which aren’t shortened down to one to three letters, especially for newer scripters trying to learn.
Something that I noticed, and that is actually pretty cool, is that we all got our preferences. It means that there isn’t actually a “professional” way to script stuff if it’s only aesthetics. If we had to talk about professional code, I’d be more talking about a way to code that helps.
Like, do you call a script with many comments professional? If the comments are really of a true use, like if you want to have a description for a function from another module, well, yea, I do somewhat agree. But if you comment like that:
local Workspace = game.Workspace -- This is where we're going to put the debris of the dead character
All you did is losing 30 seconds to write a comment that will helps a terribly small minority (+ this example with probably cause WW3 for some reasons). And it’s not productive. At all. Comments must only come to help if they are really needed, not to be the script’s mascara.
So, yea, if you want to publish stuff, you’re greatly advised to follow certain norms so most scripters on the internet can help you without being lost. But when it’s up to you, the most professional code is the one that allows you to be efficient.
I think comments are helpful, I personally write them to set the start of “Services”, “Strings”, etc.
But I also use comments to describe functions, which I found helpful when I’m making many functions or just to remember what the function does.
True but false at the same time, asserts, yes do catch bugs but they throw “errors”, which can stop your code functionament, I would not use them always.
The best way to remember what a function does is to give it a descriptive name. Your code should comment itself.
Also the whole point of an assert is to crash your program or in Roblox, throw and error. This is because if an assert is trigger, it means there is a bug in your code, it’s to help you catch bugs quickly.
That’s just an opinion. Countless developers use other programs like just simply Studios in general. I think it’s a personal preference and the scale of the project you’re working on.