Hey all! Sorry in advance if the tone of this post comes off as a little frustrated, I’ve just been racking my brain on this for a couple of years at this point and it seems like nobody giving out advice on this subject actually has any idea what the point of a Switch Statement is.
Since Lua has no native Switch Case support, and every answer I’ve found from other sources have left me dissatisfied (they ALL wind up using elseifs and let whatever program they’re using determine which case to use in some way or another), I’ve decided to just try and come up with my own.
Say we want to turn a character Left or Right using a single function in ContextActionService…
A pretty common way I've seen it written out looks something like this...
function Turn(action, state)
if action == 'Left' then
if state == Enum.UserInputState.Begin then
turnDir += 1
elseif state == Enum.UserInputState.End then
turnDir -= 1
end
elseif action == 'Right' then
if state == Enum.UserInputState.Begin then
turnDir -= 1
elseif state == Enum.UserInputState.End then
turnDir += 1
end
end
end
It works, but it looks rather messy and there’s a bit of repetition going on (repeated references to the same variable, virtually identical nested if statements), and performing checks like this causes whatever is doing the checking to perform in serial, comparing each and every argument down the line until it reaches one that is true.
Many devs – both on-site and from external sources like StackOverflow – would also have you split functions up and continue to use if statements (ternary or otherwise).
The method many people like to use to emulate a switch statement usually goes like this...
function TurnCases(state)
if state ~= Enum.UserInputState.Begin and state ~= Enum.UserInputState.End then return end
return {
Left = if state == Enum.UserInputState.Begin then 1 else -1;
Right = if state == Enum.UserInputState.Begin then -1 else 1;
}
end
function Turn(action, state)
local case = TurnCases(state)
if (case) then
turnDir += case[action]
else
turnDir += 0
end
end
Honestly, this looks even worse. Not only is there a bunch of redundant garbage clogging up memory, it still does nothing to reduce the amount of instructions – if anything, it adds more overhead.
And so, after some tinkering of my own, I present to you:
An actual switch statement in Lua.
Ex. 1 (as a variable):
function Turn(action, state)
turnDir += ({
[state ~= Enum.UserInputState['Begin' or 'End']] = 0; -- Default
[action == 'Left' and state == Enum.UserInputState.Begin] = 1; -- Cases
[action == 'Left' and state == Enum.UserInputState.End] = -1;
[action == 'Right' and state == Enum.UserInputState.Begin] = -1;
[action == 'Right' and state == Enum.UserInputState.End] = 1;
})[true]
end
Ex. 2 (as a function):
function Walk(action, state)
({
[state ~= Enum.UserInputState['Begin' or 'End']] = task.wait; -- Default
[state == Enum.UserInputState.Begin] = function() -- Cases
moving = true
while task.wait() do
if not moving then break end
local rotation = rootPart.Orientation.Y
Xdir = if action == 'Forward' then -math.sin(0.0174532925*rotation) else math.sin(0.0174532925*rotation)
Zdir = if action == 'Forward' then -math.cos(0.0174532925*rotation) else math.cos(0.0174532925*rotation)
end
end;
[state == Enum.UserInputState.End] = function()
if keyHeld('W') or keyHeld('S') then return end
moving = false
Xdir = 0
Zdir = 0
end;
})[true]()
end
(v Edit v)
It’s best to construct the switch tables outside of their respective functions, unlike what I did with my little rush job, as @sleitnick helpfully pointed out in his reply below.
(^ Edit ^)
Since every case is inside the table, including the default, there’s no need for any sort of iteration through each case. There is only one case in the table that can be true at a time, and that case gets pushed up to the top, therefore:
- No unnecessary checks need to be made.
- No questions need to be asked.
- No more wondering why you got the wrong result due to some misplaced check.
“Are we pushing a button? Are we releasing a button? Are we supposed to go a certain direction? Which direction? Yes? No? What am I supposed to be doing?” – It doesn’t matter.
Everything is laid out in simple “WhenActive → DoThing” terms
Computers aren’t very smart. It’s not a good idea to let them decide for themselves most of the time. YOU TELL THEM what to do. At least until AI takes over all the important management positions.
“You’re pushing X button, so I’ll move in Y direction.” Simple as.
NOTE: If statements definitely still have their uses. They’re often much better and faster at doing very small-scale checks (E.G. you’re just checking if a player’s health is above, below, or has reached a certain value).
HOWEVER: For deeper, more advanced checks, the constant lookup time of a table has far more benefits than it does drawbacks.
For instance: The result of clicking a button in a menu with 2 or 3 dozen options would be displayed much faster with a switch statement than it would with an if statement. Same as any scenario in which you have to compare a lot of values to an argument.
I think it goes without saying that a little more consistency and a little less repetition makes for a smoother experience, both for the user and the person writing the code.
Thank you for coming to my Ted Talk
Other edits: spelling/grammar