Avoid using else / elseif - Make your code smaller and more efficient (For beginners)

Lets just say I wanted to find out if the player won the race or not, and you are scripting the UI. The common solution would be to script something like this:

game.ReplicatedStorage.SendScore.OnClientEvent:Connect(function(Win)
   if Win == "Win" then
      script.Parent.Text = "You beat your previous time"
      script.Parent.Parent.Music.SoundId = "rbxassetid://6808979425"
   elseif Win == "Loose" then
      script.Parent.Text = "You didn't beat your previous time"
      script.Parent.Parent.Music.SoundId = "rbxassetid://6784305960"
   end
   script.Parent.Parent.Visible = true
   script.Parent.Parent.Music:Play()
end)

But lets just say that this is not the most efficient solution, and you will learn later on that doing this will be very inefficient, especially if you have like 10 different possible outcomes. The solution to this would be to use a table that will store the winning message, and another table that would store the sound ID.

How to shrink the code?

  1. Create the table(s). If you don’t know what a table is or how to use it, you can read this Developer Hub article:
local Messages = {Win = "You beat your previous time", Loose = "You didn't beat your previous time"}
local Music = {Win = "rbxassetid://6808979425", Loose = "rbxassetid://6784305960"}
  1. Now watch this! We will now shrink the code by getting a value in the table!
local Status = "Win" -- This will be the default outcome here.

game.ReplicatedStorage.SendScore.OnClientEvent:Connect(function(Win)
   script.Parent.Text = Messages[Status]
   script.Parent.Parent.Music.SoundId = Music[Status]
   script.Parent.Parent.Visible = true
   script.Parent.Parent.Music:Play()
end)

If you had 10 elseif’s then, it would be a massive improvement.
Full code:

local Messages = {Win = "You beat your previous time", Loose = "You didn't beat your previous time"}
local Music = {Win = "rbxassetid://6808979425", Loose = "rbxassetid://6784305960"}

game.ReplicatedStorage.SendScore.OnClientEvent:Connect(function(Win)
   script.Parent.Text = Messages[Win]
   script.Parent.Parent.Music.SoundId = Music[Win]
   script.Parent.Parent.Visible = true
   script.Parent.Parent.Music:Play()
end)

Now lets get a better example with at least 10 elseif’s.

I created this random game, that lets people press a button, and when they press the button, it shows on the text label the value.


However, I made them say three instead of 3, so here is the code:

local ReplicatedStorage = game:GetService("ReplicatedStorage")

ReplicatedStorage.ButtonPressed.OnServerEvent:Connect(function(Player, TheButtonsText)
	if TheButtonsText == "1" then
		ReplicatedStorage.DaAllClients:FireAllClients(Player.Name.. " Pressed one.")
	elseif TheButtonsText == "2" then
		ReplicatedStorage.DaAllClients:FireAllClients(Player.Name.. " Pressed two.")
	elseif TheButtonsText == "3" then
		ReplicatedStorage.DaAllClients:FireAllClients(Player.Name.. " Pressed three.")
	elseif TheButtonsText == "4" then
		ReplicatedStorage.DaAllClients:FireAllClients(Player.Name.. " Pressed four.")
	elseif TheButtonsText == "5" then
		ReplicatedStorage.DaAllClients:FireAllClients(Player.Name.. " Pressed five.")
	elseif TheButtonsText == "6" then
		ReplicatedStorage.DaAllClients:FireAllClients(Player.Name.. " Pressed six.")
	elseif TheButtonsText == "7" then
		ReplicatedStorage.DaAllClients:FireAllClients(Player.Name.. " Pressed seven.")
	elseif TheButtonsText == "8" then
		ReplicatedStorage.DaAllClients:FireAllClients(Player.Name.. " Pressed eight.")
	elseif TheButtonsText == "9" then
		ReplicatedStorage.DaAllClients:FireAllClients(Player.Name.. " Pressed nine.")
	elseif TheButtonsText == "10" then
		ReplicatedStorage.DaAllClients:FireAllClients(Player.Name.. " Pressed ten.")
	end
end)

Woah there… That is a lot of elseifs, making it 25 lines of code. If you were to hire a professional scripture, it might take them a while to read that, and they might demand higher pays due to the pain (As I read through portfolios, they don’t like working with code like this.) Now lets simplify this code:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local NumberTable = {
	["1"] = "One",
	["2"] = "Two",
	["3"] = "Three",
	["4"] = "Four",
	["5"] = "Five",
	["6"] = "Six",
	["7"] = "Seven",
	["8"] = "Eight",
	["9"] = "Nine",
	["10"] = "Ten",
}

ReplicatedStorage.ButtonPressed.OnServerEvent:Connect(function(Player, TheButtonsText)
	ReplicatedStorage.DaAllClients:FireAllClients(Player.Name.. " Pressed ".. NumberTable[TheButtonsText])
end)

This here is only 17 lines of code, and it a lot more organized, plus, if you wanted to, you can make the table only 1 line! Professional scripters (like me) like working with this code rather than the elseif spam.

So long story short, use tables and not elseif. If you would like me to convert your code that uses elseif to code that uses tables, hit this topic with a reply!

Still confused? Feel free to make a reply and I will hopefully help you, and others! I was confused with tables and used to code with elseif.

Happy coding!
-WE

35 Likes

On this part here you could shrink it down to 5 lines

local ReplicatedStorage = game:GetService("ReplicatedStorage")

ReplicatedStorage.ButtonPressed.OnServerEvent:Connect(function(Player, TheButtonsText)
	ReplicatedStorage.DaAllClients:FireAllClients(Player.Name.. " Pressed the button that says `".. TheButtonsText.."`")
end)

but otherwise i found this usefull! Tho i will still use else/elseif.
else for if BoolValue then lines and elseif for things such as checking if a certain player says something and have the script do a different thing than it would for another

6 Likes

Smaller does not necessarily equate efficient or better and I don’t think it’s sound advice, or at least from just a cursory read of the title alone, to discourage else(if) clauses. There are a lot of cases that can be solved in different ways but they still have their respective uses.

For your messages/music example, you’ll probably find it’s more consistent and better to use a single table that contains win/lose data instead of creating two different tables for them. You can then access the respective condition’s table to get info. See:

-- Use GetService for services. Stay consistent.
local ReplicatedStorage = game:GetService("ReplicatedStorage")

-- This is our table. Different index, same structure.
local STATUSES: {[string]: {Message: string, MusicId: number}}
    Win = {Message = "You beat your previous time", MusicId = 6808979425},
    Lose = {Message = "You didn't beat your previous time", MusicId = 6784305960}
}

-- This is what we'll connect to OnClientEvent.
local function showStatus(status)
    local statusInfo = STATUSES[status]
    -- Don't assume the status you want exists. Check if it does.
    -- Elseif can be good for multi-level guard clauses/assertions.
    if not statusInfo then return end

    -- It'd be better for organisation not to put this script in a TextLabel. :(
    -- If you put it higher, you won't have to write parent so much.
    script.Parent.Text = statusInfo.Message
    script.Parent.Parent.Visible = true
    script.Parent.Parent.Music.SoundId = "rbxassetid://" .. statusInfo.MusicId
    script.Parent.Parent.Music:Play()
end

-- SendScore:FireServer("Win")
ReplicatedStorage:WaitForChild("SendScore").OnClientEvent:Connect(showStatus)

Just a heads up there in designing strictly for efficiency or smallness. You also want it to be readable and effective in doing what you need it to do.

27 Likes

I really think if I put that, beginners really wouldn’t understand, so that is why I used mine instead of that, but maybe your table might make sense to beginners. This tutorial is meant to teach people to avoid using else / elseif, and how to do it.

1 Like

are there any cases where elseif’s are needed?
i usually just use multiple if statements and I feel like else is more useful then elseif

I NEVER use elseif so if I remember right they still run if the past statement was false or true

Else and elseif aren’t needed unless you wanted to make your code long and unorganized.

I’m talking about elseif not else

also I’m just asking the difference between multiple if statements and elseif statements

That’s why you add comments throughout code to help others see what your code is doing and which parts are responsible for what. The only thing that isn’t quite beginner friendly is my addition of typechecking on the table but that’s fairly negligible. :slight_smile:

It’s good to teach best practice early on so newer developers get into good habits. You can consolidate your tables into data tables instead of having separate tables for each item.

1 Like

At this point you are villainizing if and elseif, there are absolutely valid use cases for them. What you are doing (dictionary dispatch) may use a bit more memory since depending on how many conditions you have you’ll have quite a large table, but probably not a big deal. Even then I think for organization purposes you should have a function that returns the “word” variant of a number.

7 Likes

Saying that the else and elseif statements is not efficient depends on the entirety of the code. A conditional statement itself is not inefficient, but rather what happens if that condition is true or if there are multiple conditions to be checked or what methods are used to test the condition.

It comes down to a per code or per structure basis. Not every else and elseif statement is inefficient. There are just the very specific occasions where not using it would save a bit of performance.

1 Like

It’s entirely possible to have shorter code that’s more inefficient that a longer block of code, so the argument that less if / else statements makes code more efficient is incorrect. Although having less statements will improve the readability and organization of code, it doesn’t have a large impact of code efficiency in most cases.

1 Like

Actually in the case you prescribed, elseifs would be faster (even in the worst case scenario where it has to check every branch before it gets to the end)
Here’s the test:

local status = "10"

wait(0.5)

local start = os.clock()

for i = 1,10000000 do
	local ae
	if status == "1" then
		ae = "One"
	elseif status == "2" then
		ae = "Two"
	elseif status == "3" then
		ae = "Three"
	elseif status == "4" then
		ae = "Four"
	elseif status == "5" then
		ae = "Five"
	elseif status == "6" then
		ae = "Six"
	elseif status == "7" then
		ae = "Seven"
	elseif status == "8" then
		ae = "Eight"
	elseif status == "9" then
		ae = "Nine"
	elseif status == "10" then
		ae = "Ten"
	end
end

print(os.clock() - start)

local statusMap = {
	["1"] = "One",
	["2"] = "Two",
	["3"] = "Three",
	["4"] = "Four",
	["5"] = "Five",
	["6"] = "Six",
	["7"] = "Seven",
	["8"] = "Eight",
	["9"] = "Nine",
	["10"] = "Ten",
}

wait(0.5)

local start = os.clock()

for i = 1,10000000 do
	local ae = statusMap[status]
end

print(os.clock() - start)

Here’s the result:
image

To be clear I’m not advocating for the use of lots of elseifs, the performance difference is negligible (unless you’re doing 100000000 of these, but then I think that points to a larger problem), and the readability costs get big

But saying that making all your if branches into tables will make it more efficient is false, you’re using more memory for the tables and as shown above will probably make it ever so slightly slower too (I haven’t tested how large an if branch needs to be to get slower than a dictionary, but you rarely need to use more than 10 if branches anyway).

2 Likes

Elseif is hugely important. There are two ways to avoid using elseif

if a then
else
    if b then
    else
        if c then
        else
        end
    end
end
if a then
end
if b then
end
if c then
end

Method two causes a performance hit since it needs to evaluate everything, even if the first one cleared the check. Don’t do that.
Method one is more proper, but it’s harder to read and (I believe) still results in an extra opcode. Use elseif.

1 Like

The title is pretty misleading and you never really explained why. You’re basically just saying shorter code = better code. This isn’t the case for what you’re talking about. In fact, there are even shorter ways to make even shorter code such as using the and, or, and not.

if 1 == 1 then
    return "1 = 1"
else
    return "1 not equal to 1"
end

--// Can be changed to

return 1 == 1 and "1 = 1" or "1 not equal to 1"

These 2 ways don’t have a difference when ran.


I believe you were probably trying to talk about code clarity and not code efficiency (as in performance). In which case, is totally up to preference.

1 Like
game.ReplicatedStorage.SendScore.OnClientEvent:Connect(function(Win)
    local Text = Win == "Win" and " " or " didn’t "
    local Id = Win == "Win" and "6808979425" or "6784305960"
    script.Parent.Text = "You"..Text.."beat your previous time"
    script.Parent.Parent.Music.SoundId = "rbxassetid://"..Id
    script.Parent.Parent.Visible = true
    script.Parent.Parent.Music:Play()
end)

not saying you should do this just saying it’s an other option

1 Like

ok that clears it up then, thanks

I didn’t care as much about that first option

2 Likes

I think more importantly to mention, as you said the difference of elseif vs. dictionary is negligible, however the flexibility + maintainability you gain by offloading it to a table is much better, not to mention I personally have an easier time reading a dictionary than elseif’s compacted in their standard form. I’m sure others may agree.

2 Likes

if you don’t mind me asking, what does the colon* do in a table? and do you have any resources for it/ explain it?

1 Like

you can use commas or semicolons to separate each value in a table

I meant Colon, my bad.":" this thing.