Lua doesn’t have true ternary operator but there is a way to mimic the behavior. This is one of the biggest issues people who aren’t used to Lua have when reading Lua code. For the most part Lua is simple and straight forward to understand. Assuming a blocky and easy to understand style is used. However, the pseudo ternary is often used and trips up people. So let’s look at it in some detail.
The core of a ternary is an
if ... else statement. In Lua, we can mimic this
and ... or with the evaluated statement. What we end of is
then use the code path after
if false use the code path after the
or. Let’s look at a simple example.
if a == nil then b else c end
This is the equivalent to:
a == nil and b or c
Let’s look at more complex logic.
if a ~= nil and (1 < 5) then b else c end
We can do the same thing with the
and ... or syntax. We just need to use
parenthesis like we would with an
if statement to separate what applies to
which part of the statement
(a ~= nil and (1 < 2 or 4-2 > 5)) and b or c
We do need to be very careful with the separation. For this to work it always
has to be
(statement) and (statement) or (statement). Notice the
or cannot be within parentheses. Here is a bad example that doesn’t work like
a ~= nil and (b or c) .. a
In this situation we’d end up with
b concatenated with
a which is expected.
a == nil, then we would end up with
false. This statement does
not have a proper
or for the
false code path of the logic. Since there is
no code path Lua returns
false for in this situation. The proper way to
handle sticking a tailing statement to the ternary is to put the entire
operation into parentheses.
(a ~= nil and b or c) .. a
Regardless of which branch is chosen we’ll always get the variable concatenated
Now let’s look at complex components components.
a ~= nil and (b .. c .. a) or (a .. c .. b) a == nil and (b .. c .. a) or (a .. c .. b)
This goes back to proper use of parentheses. We have the decision, the
or outside of any parentheses and the code paths themselves within to
properly contain the logic.
Let’s put together some samples we can run to really demonstrate everything that’s been covered.
local a = "123" local b = "xyz" local c = "test" print("Simple if") if a == nil then print("", b) else print("", c) end print("Equivalent simple ternary") print("", a == nil and b or c) print("Complex if") if a ~= nil and (1 < 2 or 4-2 > 5) then print("", b) else print("", c) end print("Equivalent complex ternary") print("", (a ~= nil and (1 < 2 or 4-2 > 5)) and b or c) print("Bad ternary") print("", a ~= nil and (b or c) .. a) print("", a == nil and (b or c) .. a) print("Proper ternary") print("", (a ~= nil and b or c) .. a) print("", (a == nil and b or c) .. a) print("Complex ternary") print("", a ~= nil and (b .. c .. a) or (a .. c .. b)) print("", a == nil and (b .. c .. a) or (a .. c .. b))
Now for the output
Simple if test Equivalent simple ternary test Complex if xyz Equivalent complex ternary xyz Bad ternary xyz123 false Proper ternary xyz123 test123 Complex ternary xyztest123 123testxyz
We should keep looking at this a bit further. In the above examples only variables were used and
they were all run though a print statement. Ternary operations should be small and will typically
only use variables. Such as using it for assignment. However, functions can be run in the
false branches and care needs to be taken.
Let’s look at an example with two functions.
print("Functions 1") function b_func() print("b_func", b) end function c_func() print("c_func", c) end print("", true and b_func() or c_func())
You might think only function
b_func would run but that’s not what happens.
b_func has no
explicit return so implicitly it returns
nil, which evolutes to false.
true run the
b_func), but since that branch returns
false it will then continue on and
false branch (
c_func). So we’ll end up with this output:
Functions 1 b_func xyz c_func test nil
Both functions ran which is not at all what we’d want to happen. Also notice that since
c_func also don’t have a return it returned
nil and since it’s inside of a
nil is printed.
This can cause problems if you’re trying to run a function that either doesn’t have
a return value or if it returns
false and you don’t care about the return.
false branch (
c_func) will only run if the
true branch (
This goes back to the fact this is not a true ternary but an evolution!
If we change
b_func to return true like so.
function b_func() print("b_func", b) return true end
Then run it again we’ll get this output.
Functions 1 b_func xyz true
This is what we want to happen with only
b_func running. We still see
true printed which
is the return of the function because we’re running the return value through
If you’re working with functions you need to be very careful with this pattern otherwise
more than you expect might run. My advise is if you’re calling functions don’t use this
pseudo ternary and instead use a true
if block. Only use this for variable assignment.
However, even with variable assignment you need to be careful with the
e = nil g = true and e or c
What do you think g will be,
If you guessed
c) you’re right. Again this
is an evaluation. Our expression is
true, go to the
and) branch. That branch
false so evaluate the
or) branch. Since it’s an or where either
c for the evaluation then
c will run whenever after
e if it is
The next question is how to assign
nil in the
true branch. As far as I’m aware
you can’t. So, use an
if statement if you need
nil assignment. It’s imperative that
you are sure variable used for assignment with this ternary pattern will never be
and any functions will either return
true or a value otherwise this won’t work
like you expect.
Hopefully this makes ternaries logic can be used in Lua clear to everyone.