from my understanding when using switch() in c it makes an array of jump instructions instead of comparing the values for each case which increases performance
I tried to do the same in luau with this code
code
local value = 0
local functions_table = {
[1] = function() value = value + 1 end,
[2] = function() value = value +2 end,
[3] = function() value = value +3 end
}
local start = os.clock()
for i = 0,1000000,1 do
functions_table[math.random(1,3)]()
end
local finish = os.clock()
local time_taken = finish-start
print("first test result = ".. tostring(time_taken))
start = os.clock()
for i = 0,1000000,1 do
local num = math.random(1,3)
if num == 1 then
value = value + 1
elseif num ==2 then
value = value +2
elseif num==3 then
value = value +3
end
end
finish = os.clock()
time_taken = finish-start
print("second test result = ".. tostring(time_taken))```
and for some reason the result was
03:53:41.807 first test result = 0.057964300038293004 - Server - Script:14
03:53:41.853 second test result = 0.0457230000756681 - Server - Script:33
This is only true for if statements that don’t have a lot of cases like yours. Computers are really good at if statements. And the lookup table has to do more work than the if statement. For example it has to first perform a lookup operation on the table, and then run the function
(sorry not a super technical explanation, but in practice if you have a table with less than like 50 values it’s always better to make it an if statement if you only care about performance)
Just for context, in lower-level languages, switch blocks can be compiled into ‘jump tables’ or ‘computed gotos’ that simply set the instruction pointer to somewhere else, so the only cost is a single lookup and a jump.
In Lua(u), you’re storing a closure in a heap-allocated array that you’re dynamically indexing and calling. Doing all that will end up totaling to being worse than a simple if branch.
Generally, you’d want to use LUTs for calculating precomputed values, not determining what calculations to do on the fly like that. Using buffers with native compilation just for that will also give you nice cache locality that’ll really speed things up (but the library call cost in normal interpreted mode might be worse).
I ran the code and realized you were adding the overhead of the function call on the table lookup part so I implemented the same on the if statement and got flipped results where the lookup was faster
local N = 100000
return {
ParameterGenerator = function()
local functions_table = table.create(3, function(value) value+=1 end)
return math.random(1, 3), functions_table
end,
Functions = {
["table lookup"] = function(_, randomNumber, functions_table)
local value = 0
for i = 1, N do
functions_table[randomNumber](value)
end
end,
["if statement"] = function(_, randomNumber, functions_table)
local value = 0
for i = 1, N do
if randomNumber == 1 then
functions_table[randomNumber](value)
elseif randomNumber == 2 then
functions_table[randomNumber](value)
elseif randomNumber == 3 then
functions_table[randomNumber](value)
end
end
end,
},
}