Make your code faster and easier to read with branchless programming!

This is a technique I’ve discovered quite recently, and it has reduced the amount of elseif statements in my code by two times.

In case you didn’t know. If statements are slow. The compiler has to process every possible path your code could go down.

You can replace a lot of elseif statements that compare strings and numbers with a table of functions that are loaded into memory instead. This is going to take less lines, run faster and be easier to read. You can learn by example using the example code below:

--CLASSIC BRANCHED PROGRAMMING
local function SaySomething(emotion,topic)
	if emotion == "Angry" then
		if topic == "Fruit" then
			print("i hate apples!")
		elseif topic == "Candy" then
			print("i hate chocolate!")
		end
	elseif emotion == "Happy" then
		if topic == "Fruit" then
			print("i love apples!")
		elseif topic == "Candy" then
			print("i love chocolate!")
		end
	end
end

SaySomething("Angry","Fruit")


--BRANCHLESS METHOD

local t = {} --keep this loaded into memory so we can overwrite it every time we want to write a "branchless branch"

local function CarAction(car,action)
	t = {
		VolvoDestroy = function()
			volvo:Destroy()
		end,
		VolvoPaint = function()
			volvo.Paint(BrickColor)
		end;
		HondaDestroy = function()
			honda:Destroy()
		end;
		HondaPaint = function()
			honda.Paint(BrickColor)
		end;
	}
	
	(t[car..action] or function()end)()
	--car..action should match one of the entries in the table above, if it doesn't then we run an empty function
	
end

CarAction("Volvo","Paint")

This isn’t a full replacement for if statements, it’s only a replacement in some cases, and it works exceptionally in those cases.

6 Likes

Saying “If statements are slow” is an over-exaggeration. From my testing using branchless programming makes so little difference it doesn’t matter.

I did some tests that time how long it takes for each method to run the same function and it does it 10 thousand times and averages it out.
Here’s the code

local function time(func,...)	
	local iterations = 10000 --// 10k
	local totalTime = 0
	local maxTime = 0
	
	for i = 1,iterations do
		local startTime = os.clock()
		func(...)
		
		local timeTaken = (os.clock() - startTime)
		totalTime += timeTaken
		if timeTaken > maxTime then
			maxTime = timeTaken
		end
	end
	warn("Total Time: "..totalTime)
	warn("Average Time Taken: ".. totalTime/iterations)
	warn("Max Time: ".. maxTime)
end

--CLASSIC BRANCHED PROGRAMMING
local function SaySomething1(emotion,topic)
	if emotion == "Angry" then
		if topic == "Fruit" then
			print("i hate apples!")
		elseif topic == "Candy" then
			print("i hate chocolate!")
		end
	elseif emotion == "Happy" then
		if topic == "Fruit" then
			print("i love apples!")
		elseif topic == "Candy" then
			print("i love chocolate!")
		end
	end
end

wait(2)
warn("Branched")
time(SaySomething1, "Happy","Candy")


--BRANCHLESS METHOD

local t = {} --keep this loaded into memory so we can overwrite it every time we want to write a "branchless branch"

local function SaySomething2(emotion,topic)
	t = {
		["Angry"] = {
			["Fruit"] = function()
				print("i hate apples!")
			end,	
			["Candy"] = function()
				print("i hate chocolate!")
			end,	
		},
		["Happy"] = {
			["Fruit"] = function()
				print("i love apples!")
			end,	
			["Candy"] = function()
				print("i love chocolate!")
			end,
		},
	}

	(t[emotion][topic] or function()end)()
	--car..action should match one of the entries in the table above, if it doesn't then we run an empty function
end
wait(2)
warn("Branchless")
time(SaySomething2, "Happy","Candy")

image

If you see here the difference between branchless and branched code is a minuscule difference.
Average is tiny and even if you look at the extremes, the max time spent, the difference is only in the milliseconds

Even consider the worst-case scenario. Say you have 70 completely random if statements like this

local function SaySomething1(emotion,topic)
	if emotion == "Angry" then
		if topic == "Fruit" then
			print("i hate apples!")
		elseif topic == "Candy" then
			print("i hate chocolate!")
		end
	elseif emotion == "edewdwdw2w" then
	elseif emotion == "edewdwdw5w" then
	elseif emotion == "edewdwdw6w" then
	elseif emotion == "edewdwdwd7w" then
	elseif emotion == "edewdwdwdw7" then
	elseif emotion == "edewdwdwd6w" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "ed6ewdwdwdw" then
	elseif emotion == "ede6wdwdwdw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edew6dwdwdw" then
	elseif emotion == "edewd6wdwdw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edew5w4dwdw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edewdwd4wdw" then
	elseif emotion == "edewdwdw44dw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "ede4wdwdwdw" then
	elseif emotion == "edew4d7dwdw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edewd46dwdw" then
	elseif emotion == "edewd54dwdw" then
	elseif emotion == "edewd4dwdw" then
	elseif emotion == "edew2wd4wdw" then
	elseif emotion == "edewdwdw4dw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "e4dewdwdwdw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "ed4ewdwdwdw" then
	elseif emotion == "ede4wdwdwdw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edew4dwdwdw" then
	elseif emotion == "edewd4wdwdw" then
	elseif emotion == "edewdw4dwdw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edewdwd4wdw" then
	elseif emotion == "edewdwdw4dw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edewdwdwd4w" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edew6dwdwdw" then
	elseif emotion == "edewd6wdwdw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edewdw7dwdw" then
	elseif emotion == "edewdwd7wdw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edyewdwdw7dw" then
	elseif emotion == "edeywdwdwdw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edewydwdwdw" then
	elseif emotion == "edewdywdwdw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edewdwydwdw" then
	elseif emotion == "edewdwdywdw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edewdwdwydw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edeewdwdwdw" then
	elseif emotion == "edewedwdwdw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edewdewdwdw" then
	elseif emotion == "edewdwedwdw" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edewdwdewdw" then
	elseif emotion == "edewdwdwedw" then
	elseif emotion == "edewdwdwdew" then
	elseif emotion == "edewdwdwdw" then
	elseif emotion == "edewdwdwdwe" then

	elseif emotion == "Happy" then
		if topic == "Fruit" then
			print("i love apples!")
		elseif topic == "Candy" then
			print("i love chocolate!")
		end
	end
end

image

The difference is still so small there is almost no difference.
Do what you want to do but you shouldn’t be discouraged from using if statements. Both are completely fine.

12 Likes

As long as you don’t become a yandere dev you should be fine :stuck_out_tongue:

2 Likes

This is definitely how it should be done - where you can :slight_smile: . But not for efficiency reasons - it is nearly exactly the same as just branching with an if statement - only when you start getting into crazy levels of hundreds of if statements will you notice a difference. The benefit here is solely readability / good code patterns.

1 Like