1
votes

I came across this question in codewars that goes like this:

Implement a function that will run 2 different functions depending on a boolean value. Of course, it can be implemented using simple if statement. Like so:

function _if(bool, func1, func2) 
    if bool then return func1() else return func2() end
end

However, it does not pass all test cases when I want to solve it using ternary operator:

function _if(bool, func1, func2) 
    return bool and func1() or func2()
end

But this works:

function _if(bool, func1, func2) 
    return (bool and func1 or func2)()
end

I think I simply don't have enough knowledge regarding Lua. I have searched through the community about this but can't find any explicit explanation about this. I was wondering if someone could shed some light on this or just suggest some articles that might help me understand.

UPDATE EDIT

Well, then how does the second snippet differ from the third one if func1 always return truthy value?

4
Lua does not have any ternary operators! It's just that and has higher precedence than or. - Piglet
see my anwer. I added some details. Please read en.wikipedia.org/wiki/Short-circuit_evaluation - Piglet

4 Answers

5
votes
function _if(bool, func1, func2) 
    if bool then return func1() else return func2() end
end

The above piece of code returns func1() if bool is true and func2() else.

The following code will return func2() if bool is not true or if bool is true and func1() is not true. It will only return func1() if both bool and func1() are true.

function _if(bool, func1, func2) 
    return bool and func1() or func2()
end

The last piece of code will return func1() if bool is true and func2() else.

function _if(bool, func1, func2) 
    return (bool and func1 or func2)()
end

So first of all, Lua does not have any ternary operator. The clever use of and's higher precedence over or is just equivalent to ternary operators like C's ?:

Second the expression a = b and c or d will only work properly if c is true. This may not always be the case if you're using a function call as c.

It's a convenient way to do assignments but in many cases it increases readability and reduces mistakes to just stick to an if else statement.

Once you have to add more conditions that and or trick becomes a total mess.

So let's have another look on what is going on in the second snippet.

function _if(bool, func1, func2) 
    return bool and func1() or func2()
end

First bool and func1() will be evaluated. If bool isn't true, Lua does not have to call func1() because the expression can never be true. So Lua can go and evaluate func2() right away. Your function will return func2()!

On the opposite, if bool is true, Lua will call func1() to see if it also true. if func1() returns true, Lua will not call func2(). Because of the following or the expression will always be true if bool and func1() is true. if func1() returns false/nil the or has to be evaluated. So Lua will call func2() as well and then return it's return value.

It is important to know operator precedence and in which cases Lua will abort evaluating expressions!

Lua's or and and operators use short-cut evaluation. The second operand is only evaluated if necessary

2
votes

Perhaps it will help you to see what is going on if you look at what happens when you only use or.

function func1()
    return true
end

function func2()
    return false
end

print(func1() or "default") -- true
print(func1 or "default")   -- function: 0x2377c80
print(func2() or "default") -- default
print(func2 or "default")   -- function: 0x2377cb0

If you use func1 or func2 without the parentheses, you get a function object, and function objects are always evaluated as true in Lua. (The only things evaluated as false in Lua are false and nil.)

0
votes

The if version is not equivalent to the second one using and

If func1() returns false the or part is evaluated and the result of func2() is returned.

The last one works (when func1 is not nil) because you call the function after you have determined which one to call. So, the bool simply selects the 'pointer' to which function to call next. Assuming func1 is not nil, the pointers will never be false.

0
votes

There several potential problems in your code. 1. As already mentoned if func1 returns any falsy value then func2 will be called. 2. bool and func1() or func2() returns exactly one result.