Ways to Simplify or Improve code

Introduction

Hi, This is just a tutorial that I am Arguing with myself whether if I should be putting in #resources:community-resources or not, But for now until proven otherwise, It will be here as a Tutorial for people to use or give to people for specific reasons, idk, its all up to you whether you want to look at this or not

This is just a combination of Data I have learned over time, I generally use these methods over others due to how simple they are to use.

Prelude

This mainly revolves around the Usage of if, elseif, and else as those are generally very overused to the point where there is so many Possibilities for one statement that it’s unnecessary.
However, there maybe other examples I will Provide, I’ll Update if I find more you can do.

A Few things to Remember However:

  • Intended For Beginners
    This Topic is intended to be for Beginners with Luau, There are plenty of well experienced people who can help with Better Methods than me.

  • Some Meanings are Simplfied
    Some of the meanings or Usages for some functions are Simplified to Help with Explanation.

  • Correct Me if I’m Wrong
    I could be wrong about some of the things I write, Feel free to Correct me if thats the case with this Tutorial. :slight_smile:

I’m not perfect, and never expect me to be so, I tend to make a lot of mistakes when it comes to this so dont just reply saying “This is bad, blah blah blah”, I am fully Aware of my mistakes if I make any, Just some be an arse about it.

Anyway, This Prelude is getting very long so lets just get started.

Start

This generally isn’t a bad thing to do the methods I’ll cover, Its just that It can be simplified or Improved on with other methods, some Methods usually take a long time to write, or take a while to get working, which is normal when scripting, as it is just a Trial and Error Process to get the Expected Result.

Although there are plenty of methods to write code, there are plenty of bad or weird things we tend to do when writing them, we tend to add unnecessary things to them when you dont have to do them as they can be change with something else, usually doing these kinds of things results in weird looking code in which you are suprised Luau even allows it, or completely inefficient code that looks completely wrong, very slow, and very unnessacary, But Again, this tutorial is intended to be toward beginners so, I’ll help with fixing those mistakes.

When it comes to efficiency, you should always choose the best methods when it comes to that, many methods you try can be very inefficient compared to many other methods, some I’ll cover here.
I have Hid the Topics so it looks Better, However you decide that.

As if currently, there is 6 Examples, I may add more to this if I feel like it.


error() if false

error() if false

We are able to check if the conditions we have are true or not with the usage of if statements (if you forgot), In this case we can just use an if statement to check if our condition is true, Like with this code example to error() our code if a statement is false:

local Active = false -- Active is false

if not Active then -- if false of nil
    error("It is not Active.") -- errors code
end -- end of if statement
-- It will ignore the if statement and continue if Active is true.

However, We dont need to do this at all, while yes, this is the “Correct way” to do it, it isn’t the best way to do it, which is where the function assert() comes in,

assert() is used to check if a statement is true or false, and even nil, we can use it to check for this, and if the statement is false or nil, it will error:

assert(Active == true, "It is not Active.")
-- Alternate Method:
assert(Active, "It is not Active.") 
-- It's probably best to check if its true with "==" instead "if this then"

assert() would be useful for this check, instead of having multiple if statements for it.

assert(Something, "Something isnt there?")
assert(Data ~= nil , "Data is nil.")
assert(Imposr , "AMOGUS")

DoSomething(Something, Data, Imposr)

Setting Minimum and Maximum Values

Setting Minimum and Maximum Values

When Setting Minimum and Maximum values, you can use an if statement to check for this like for Example:

if Number > Maximum then -- if number is greater than the Max Value
    Number = Maximum
end
if Number < Minimum then -- if number is less than the Min Value
    Number = Minimum
end

But again, we dont have to use this, you are able to use the math functions math.min and math.max for this.

math.min will get the minimum Number, while math.max will get the maximum Number.
(You you didnt get that already, If you did, Good Job!, If not… Good Job!)

So for this, we can use these functions to set a limit for our number, like this:

local Maximum = 10

-- Limit for Higher values
Number = math.min(Maximum, Number)

This works as we are checking for the smallest value, if Number is smaller, it will return Number, however if 10 is smaller, it will return 10 as the new number, so it will automatically apply the Maximum Value, the same can be done with the Minimum Value with math.max

local Minimum = 0

-- Limit for lower values
Number = math.max(Minimum, Number) -- returns the Hightest value

However, it wouldn’t be great if we used both math functions for this task, instead, we have math.clamp for this where we can combine both of these functions together to limit the number.

  • The First Argument is the Number we Currently have
  • The Second Argument is the Minimum Number that the number can’t pass
  • The Third Argument is the Maximum Number that the number can’t pass
local Minimum = 0
local Maximum = 10

Number = math.clamp(Number, Minimum, Maximum)

Resetting Numbers

Resetting Numbers

When reseting numbers, we can simply check when the number has reached a limit:

if Number >= Limit then
    Number = 0
end

However, this can also be simplified by using the Modulo (or Modulus) Operator which is the % symbol.

Now, what does this do?
Modulo Simply returns the Remainder in Divison, we can use this to reset a number once it has reached a limit, so for Example:
10 % 11 = 10
11 % 11 = 0
We can use this to reset numbers when they reach a limit, and plus, if they dont, it wont affect your number, so it can be useful:

Number %= 10 -- if number is equal to 10, it will go back to 0

This can also be useful to 12 Hour Clocks when you want to set the hour from 12 to 1:

local Hour = 12
Hour = (Hour % 12) + 1
-- Number will reset to 0 but + 1 is added to the mix so it will be 1

Setting up Timers

Setting up Timers

When setting up a Digital Clock of some sorts, we would need to check if they number has reached a limit, like for example, if a number is less than 0, we should Add a 0 at the beginning to determine that, if a number has hit a limit, reset it, like with this:

local Sec = 0
local Min = 1

local SecFormat = Sec
local MinFormat = Min

if Sec < 9 then -- if number is less than 9
    SecFormat = "0"..Sec -- formats Seconds
end
if Min < 9 then -- if Minutes are less than 9
    MinFormat = "0"..Min -- formats Minutes
end
if Sec > 59 then -- if number is greater than 59
    Sec = 0 -- resets
    SecFormat = "0"..Sec -- also formats Seconds
end

local Time = MinFormat..":"..SecFormat -- concatenates our numbers

Although this is correct, it isnt efficient, we have to constantly check if the number is less or more than something, so instead, we will use string.format for this, now what is this and how to we use it?

so string.format is exactly what it sound like, it formats a string, we can use this to set up a format where we have a real Timer instead of adding on 0’s, For this we will use the Following Specifiers:

  • %d or %c to represent a number
  • %02i Adds Padding of 0’s
    Ex: 1 + format(%02i) = "01", 10 + format(%03i) = "010"

Which you can basically find this information here.

So now, If we put these formats together, we now have this:

-- ... is a placeholder just to remind you.
string.format("%d:%02i", ...) -- our format
-- Alternate method:
("%d:%02i"):format(...) -- also our format

Wwith this, we can now have a accurate representation of a timer without the need to manually check it manually, but we still have to check out minutes and Seconds, We will use the Topic above (Ressetting Numbers) to help us with this:

-- finally, an actual use for an if statement
if Sec == 0 and Min == 0 then return end

if Sec > 59 then -- if Seconds is greater
    Min += 1
elseif Sec < 0  then -- if Seconds is less than 0
    Min -= 1
end

Sec %= 60 -- resets number to 0 or 59
-- you can add this for Minutes as well, Up to you tho :)

Timerformat = string.format("%d:%02i", Min, Sec) -- formats numbers
print(string.format("%d:%02i", 1, 1)) --> "1:01"
print(string.format("%d:%02i", 12, 59)) --> "12:59"

This will significantly simplify and improve your code :slight_smile:


Absurd amount of elseifs

When using if statements, you generally use them for one purpose, not multiple, but if you do, you have else and elseif to help with this.

However, It is never a good idea to place elseifs everywhere within a statement, thats how you make your code look ugly and hard to read, Instead you should try using Arrays, or Create a function for the statements rather than placing elseif left and right

What NOT to do;

if Statement then -- this statement is ugly
elseif Statement then
elseif Statement then
elseif Statement then
elseif Statement then
elseif Statement then
elseif Statement then
elseif Statement then
elseif Statement then
elseif Statement then
elseif Statement then
elseif Statement then
elseif Statement then
end

Typewriting Effects

Typewriting Effects

No, This isnt here because of Another Topic
And No, This isnt to hate the person who did this, but still, what you did was kind of stupid.

If you arent aware, I made a Tutorial about Typewriter Effects which will cover a lot of what I will say here.

2 Method's for a Typewriter Effect

It is also In my Featured Topics right now, if you want to, check it out.

When making Typewriter Effects, You usually do it will specific Methods like with a for loop, but it is never a good idea to be doing this:

TextLabel.Text = "Hello"
task.wait(.1)
TextLabel.Text = "Hell"
task.wait(.1)
TextLabel.Text = "Hel"
task.wait(.1)
TextLabel.Text = "He"
task.wait(.1)
TextLabel.Text = "H"
task.wait(.1)
TextLabel.Text = ""

(But dont worry, I bet you got that too, if so, good job! you’re so smart!)
This would make code long and inefficient and would be great at all, instead we use a for loop with string.sub to have this same effect.

  • First Argument is our string

  • Second Argument is the Start of where the string is, starting on the character
    Default is 1 meaning the first Character

  • The Third Argument is the Target, basically the character the string will stop
    Default is -1 meaning it starts at the very end, However it can be reversed to just the last character in out string, so if we have Hello, we can put it as -1 or 5.

for i = #Text,0,-1 do -- iterates for the number of letters in the string
-- 0 is our Target Number to reach
-- the third argument for -1 is for the index to go down
    task.wait(.1) -- waits .1 seconds
    TextLabel.Text = string.sub(Text, 1, i) -- subtracts from string
end

This would be a way better method for this rather than the other!


Conclusion

There is no Really much to say, Just Hi.

I basically already have said what there is need to be said, These may help with with scripting, maybe you didnt know these methods, Maybe you didnt understand this, But thats fine. You can always learn more.


Thoughts

I would like to know what you think!

Your Thoughts?
  • Useful
  • Good
  • Ok
  • Bad
  • Terrible

0 voters


Whatever I put here?

This Section is just whatever, could be Off Topic, Could be useful.


Nothing to See here
Seriously, nothing to see here
Come on bro, not this again
I'm Serious
stop.
Stop.
Stop!
Stop!!!
STOP!!!
PLEASE!!
STOP IT!!!
YOU'RE KILLING ME!!!!
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Honduras


math.random() for Arrays

math.random() for Arrays

for some reason, people dont know how to do this with Arrays, where you can get the Random Index from math.random()

Food = {"Orange", "Apples", "Bannana"}

local RandomFood = Food[math.random(1, #Food]) -- Gets Random Index between 1 and the Number of Items in the Array

print(RandomFood) -- "Orange", "Apples", "Bannana"? (Result is Random)

23 Likes

Or just ask chat GPT to make ur code better

2 Likes

ChatGPT aint big brain yet tho

/:

10 Likes

ChatGPT is out of its capacity at the moment and as is pretty well known around the internet, it won’t help you efficiently with the questions you have in mind compared to an actual human!

3 Likes

assert is actually a bad practice, not kidding.

2 Likes

Tested, you arent wrong.

Oh well.

It appears to be around a .00005 difference after testing 10000 times for each

It’s also just not very good when handling things. I made my own “multiple assert” function that loops through tuple of arrays, where index 1 will s the assertion, and 2 is the value.

1 Like

Great job doing this little tutorial! I have 50/50 on the topic and seems pretty useful to improve tons of processes whenever writing a script with the following tips. :star_struck:

Some little things that got me curious are…

  • If it is fine to use warn() and not precisely (i.e. always) error();
  • Is it really necessary to talk about the absurd uses of elseif during if statements? Because it seems to be just an alternative to creating an “inverted statement” and we can simply use else (when necessary, of course);
  • Regarding resetting numbers, isn’t it practical to set them as arrays so whenever time, we can choose a value (with brackets) to modify its number to return to its square zero?

There are a few parts where they are edited wrongly such as the last part mentioning the math.arrays → RandomFood and the bullets talking about what to put inside of math.clamp parenthesis… However, it is not a problem for you for sure!

1 Like

Maybe.

I am not exactly sure what you mean but I think using % is faster than having to check within an Array

Thats coming from both Documentation and Code Sample:

clamp(x: number, min: number, max: number): number

However, I did accidentally say “add” which isnt true at all, as at the time of writing it, I meant this:

Number = math.clamp(Number + 1, Minimum, Maximum)
1 Like

I meant to say like this:

local Number = {0, 1, 2, 8, 10}
local Limit = Number[5]
local NewLimit = Number[1]

if Number >= Limit then
    Number = NewLimit
end

Something like this that I had in mind (the code can be wrong, but as I am one the phone, I cannot see the proper types of table to put in the code quote. Sorry!)

It is, you are trying to check if an Array is greater than or equal to a number without using the # operator

1 Like

I believe this is the best guide for advancing scripts, Back then, I used to do some functions, and now I use assert(), and You even showed some replacements to deprecated content, like you would use DoubleConstrainedValue, and now you use math.clamp()

Anyways thanks for this tutorial

25,000/25,000

It’s actually not wrong to write these statements, since what’re you going to write instead? What mostly matters is what’s inside each statement, since if the code is too long you can put it in a module script or a function.

I don’t believe it’s good to use error when it’s outside a pcall because it terminates the entire script process will terminate.

This is why I use warn() instead of error() and assert() when testing my code.

If you make a function for the if statements, you would still have to write the long if statement inside the function. And I do not see much use cases on how a function with excessive and specific if statements would be used more than once.

Wouldn’t a loop be needed in order for the timer to work?

1 Like

you forgot two things to make the code more clean

And these are:

  1. erasing an instance’s children by using an built-in function
-- Bad Usage
for i, v in pairs(instance:GetChildren()) do
   v:Destroy()
end

-- Good Usage
instance:ClearAllChildren()
  1. Using the new string interpolation
-- Bad Usage
print("hi " ..tostring(workspace)) --> hi workspace

-- Good Usage
print(`hi {workspace}`) --> hi workspace

Be wary about your choice of wording. There are a few instances where you’re compounding and confusing efficiency, performance, readability (also: simplification) and maintainability. Some of these improve the overall look of the code but they aren’t necessarily improvements if your use of the word improvement is geared towards a technical level rather than an appearance one.

Also a personal recommendation regarding the prelude: it’s okay to be wrong, but it’s not a good look for a tutorial thread to immediately get defensive about incoming feedback. Putting flavour text at the start is a bit distracting from the main point since it takes more reading to get to what the content is about. It should primarily be a primer - perhaps a brief blurb about motivation or expected contents.


Regarding the “setting up timers” section: concatenation is faster than formatting. I’m not entirely sure I’d call the code sample inefficient but format is a cleaner way to deal with it because you can use zero padding formatting in one call. The heavy lifting in the original sample comes from the type casting.

For calculating your timer if you want to display it in MM:SS format, you should be making use of pure arithmetic operators to derive your values. This is another case where the better answer in terms of appearance is not necessarily more efficient (compared to a conditional check and quick addition, you’re using other slower arithmetic operators like division) but it helps in other areas such as maintainability and good habits when working with numbers.

More importantly though, when working with timers you should always be thinking in terms of seconds because that’s how most or all APIs are designed. You only ever need a variable for other components of time if your use case calls for it, but no time is not where you’d want to have an if statement.

local someTime = 145 -- Measured in seconds

-- 60 seconds in a minute, always round down.
local minutes = math.floor(someTime/60)
-- Find out how many seconds our minutes are worth and subtract
-- them from the initial time to find out how many seconds leftover.
local seconds = math.floor(someTime - (minutes*60))

local timeFmt = string.format("%.2d:%.2d", minutes, seconds)
print(timeFmt) --> 02:25

If you wanted to add hours, add a few more parts. Remember that someTime is still a value in seconds, so we work in terms of those seconds:

-- 3600 seconds in an hour, always round down.
local hours = math.floor(someTime/3600)
-- 60 seconds in a minute, find out how many minutes we have then
-- find out how many minutes are hours are worth and subtract that
-- to find out how many minutes leftover.
local minutes = math.floor((someTime/60) - (hours*60))
-- Find out how many seconds our minutes and hours are both worth
-- and subtract that from the initial time to get our seconds leftover.
local seconds = math.floor(someTime - (minutes*60) - (hours*3600))

Trying to find “simplicity” alone can be a noob trap for writing idiomatic code with good or best practices, nevermind the issue of “simplicity” not having an objective measure in most or all cases (it’s caused quite a few arguments on the forum!). Sometimes it’s the threads that say “simplify your code” that end up giving not-so-great advice by ignoring other pretty important aspects of code writing like readability and maintainability.

I think that these resources that try to be a widely-scoped article on common things developers do and the alternatives that can be found in them are huge noob traps in themselves. There’s a reason some of them are called alternatives and not “best practice”, but resources like this can confuse or compound the two. You can get the most out of writing resources that have a clear focus on one specific major aspect of development, such as my FindFirstChild thread that also ties into understanding replication (although, kettle and the pot, there’s a bit of my own dogma in it).

6 Likes

I’ll keep that in mind

I see your point, but Im just saying dont be rude about it if I’m wrong or make mistakes, there are generally people who are like that, I put it there as its more of an Important thing to note.

I also did say that there may be better methods from more experienced people (I was referring to a Couple of like you) so yeah, Thats bascially true

Yep, this is more on the “Simplify” part rather than the “Improve” part, they arent always the best methods but its a good thing to know at least, even if they are slower.

However thats the purpose of Feedback, so I cant really do anything about that, I made this just kind of for fun and to learn if there is better ways of doing this.

IMO it usually simplifies code very efficiently. And chatGPT is pretty good with Lua in general.

chatgpt is absolutely horrible at making roblox code that is better than a simple demo, I was just using it and it made this

local Players = game:GetService(“Players”)
local MessagingService = game:GetService(“MessagingService”)

– Function to handle player chat messages
local function onPlayerChatted(player, message)
– Create a new message to broadcast
local newMessage = {
Sender = player.Name,
Message = message,
}

-- Publish the message to every server's chat
MessagingService:PublishAsync("GlobalChat", newMessage)

end

– Connect the onPlayerChatted function to the Players.PlayerChatted event
Players.PlayerChatted:Connect(onPlayerChatted)

– Create a remote event to handle chat messages from the server
local chatEvent = Instance.new(“RemoteEvent”)
chatEvent.Name = “ChatEvent”
chatEvent.Parent = game:GetService(“ReplicatedStorage”)

– Function to handle chat messages from the server
local function onChatEvent(player, message)
– Broadcast the server message to every player’s chat
for _, p in pairs(Players:GetPlayers()) do
p.Chatted:Fire(message)
end
end

– Connect the onChatEvent function to the chat event
chatEvent.OnServerEvent:Connect(onChatEvent)

– Listen for new players joining the game
Players.PlayerAdded:Connect(function(player)
– Subscribe the player to the GlobalChat topic
local subscription = MessagingService:SubscribeAsync(“GlobalChat”, function(message)
– Send the message to the player’s chat
player.Chatted:Fire(string.format("[%s]: %s", message.Sender, message.Message))
end)

-- Unsubscribe the player from the GlobalChat topic when they leave the game
player.CharacterRemoving:Connect(function()
    subscription:Unsubscribe()
end)

end)

1 Like

It really doesnt tho.

While yes it is cool, the stuff it can either be broken, slow, or even useless code.

Its not perfect, However it may get better in the future.