I'm toying with Lua and using https://www.luac.nl/ to see how it translates to bytecode. I wanted to see if a pattern like if boolean_always_true then ... end
where the boolean was defined with <const>
would get optimized. Same for always false boolean.
local always_true <const> = true
local always_false <const> = false
function foo()
if always_true then
print("Hello World!")
end
end
function bar()
if always_false then
print("Hello World!")
end
end
ends up being
function foo() --line 4 through 8
1 GETTABUP 0 0 0 ; _ENV "print"
2 LOADK 1 1 ; "Hello World!"
3 CALL 0 2 1 ; 1 in 0 out
4 RETURN0
function bar() --line 10 through 14
1 LOADFALSE 0
2 TEST 0 0
3 JMP 3 to pc 7
4 GETTABUP 0 0 0 ; _ENV "print"
5 LOADK 1 1 ; "Hello World!"
6 CALL 0 2 1 ; 1 in 0 out
7 RETURN0
Why does the always_true
case gets optimized and the if
disappears but the always_false
case doesn't?
I tried different configurations of the code and looking at the produced bytecode with https://www.luac.nl/. I was expecting bar
to just be RETURN0
This has nothing to do with <const>, you can use an old version of Lua (<= 5.1.4) to test the code below:
function bar()
if false then
print("Hello World!")
end
end
And you will see an optimized result:
JMP 3 ;jump to return
GETGLOBAL 0 -1
LOADK 1 -2
CALL 0 2 1
RETURN 0 1
Very good, right? But an issue is hidden here. As is well known, the logical operators in Lua (and
, or
) are quite unique. In fact, they share the same logic as some statements such as if-else
, and jumping up directly causes such a bug:
-- version <= 5.1.4: nil
print(((nil and nil) or false) and true)
Due to the fact that the left expression ((nil and nil) or false
) of the last and
is clearly falsy, lua skips evaluating the value of the expression, resulting in some slight deviations in the final result. So lua's solution is to always evaluate falsy expressions.
You may ask if there is a better solution, and I think there must be, but you also need to know that lua has very few developers.