Now, when it comes to short-circuiting values, Lua does indeed short-circuit. For example:
function hello() print('hello') return true end function bye() print('bye') return false end if(hello() or bye()) then print('check to short-ciruit') end
hello
check to short-circuit
As you can see, the bye
function was not called and thus that is proof that short-circuiting occurred. Now one way to get around this short-circuiting is to preferably set a reference to the function values before-hand.
For example:
function hello() print('hello') return true end function bye() print('bye') return false end local x = hello() local y = bye() if(x or y) then print('check to short-circuit') end
hello
bye
check to short-circuit
Now, as you can see in this example, both values from the hello and bye methods were printed.
I do understand how short-circuiting occurs when you only have simple conditional statements, but when you bring other factors involved, I'm still a bit addled on it. I want to know why setting the variables before hand makes a difference, and just a more clear explanation on how evaluation in Lua works. Any links too would be really appreciated.
How does evaluation in Lua work? Why did referring to the methods before-hand cause short-circuiting not to occur?
I want to know why setting the variables before hand makes a difference, and just a more clear explanation on how evaluation in Lua works.
Alright. I'll see what I can do.
Short-circuit evaluation is when a later operation in a boolean statement is not evaluated because a previous operation in that same boolean statement is true. It is merely where the language does the minimal amount of evaluating to figure out the result of a boolean statement.
Note in a boolean statement. When point a variable to the result of an operation before the boolean statement happens, then the operation has already been evaluated.
There are no take backs in Lua; just because the result of that operation may evaluate to false
in a later boolean statement, does not mean that the operation never happened.
Notice in your code...
function hello() print('hello') return true end function bye() print('bye') return false end local x = hello() local y = bye() if(x or y) then print('check to short-circuit') end
... you set x
and y
to the results of hello
and bye
. You know this because you wrote hello()
and bye()
.
Notice that you called both of them. That means that those variables are now pointing to the evaluated results of the functions. You can check this by inserting a print statement between your local declarations and your if statement.
Remember that there are no take backs. This means that by the time you reached that if statement if (x or y) then
, you already evaluated hello and bye. This means that naturally, those functions have already run once and printed out "hello" and "bye".
This is not a matter of short-circuiting, but more of a matter of you messing something up and attributing it to short-circuiting.
Evaluating boolean statements in Lua is as logical as it gets. Everything in Lua follows the standard properties of booleans, and there are no gotcha moments when working with Lua.
That being said, since you are asking this question, I'll give you a brief overview of how Lua works with boolean statements anyway.
The following will be considered false
:
false
nil
Any variable pointing to false
or nil
Everything else is true
. That means that 0
, ""
or ''
(empty strings), and {}
(empty tables / data structures) will also evaluate as true, unlike in many other programming languages.
Here are some basic truth operations and their results...
print(true and true) --> true print(true and false) --> false print(false and true) --> false print(false and false) --> false -- or returns true if BOTH statements are true -- or returns false if ONE or more statements are false print(true or true) --> true print(true or false) --> true print(false or true) --> true print(false or false) --> false -- or returns true if ONE or more statements are true -- or returns false if BOTH statements are false print(not true) --> false print(not false) --> true -- not returns the opposite of whatever is to the right of it -- not takes precedence before and/or operations.. so -- print(not true or false) will print false
You may know that Lua does not have a true implementation of ternary operators. However, you can get by with a pseudo-ternary operation that Lua does support.
For most purposes, a and b or c
will suffice. Lua will go from left to right and evaluate each statement. It will return the last statement in a combo of true
statements connected by and
s if the statement is true
. Otherwise, it will keep going.
Here is an example...
print(true or false) --> true -- notice how it is the last true statement print(1 and 2 and 3 or false) --> 3 -- 1 is true, 2 is true, and 3 is true. -- Notice how 3 is then followed by an or. -- This makes 3 the last true statement in a string of true statements. print({} and 2 or true) --> 2 -- {} is true and 2 is true. -- Same logic as above. -- Even through the next statement is true, -- 2 is the last true statement in a combo of true statements connected by ands. print(1 and 2 and false or 3) --> 3 -- 1 and 2 are true but false is not true. -- Therefore, we go on to the next and find that 3 is true. print(false and nil or false or 1 and 2 and false or 3) --> 3 -- 1 and 2 may be true, but remember that false is not. -- Therefore, 3 is returned.
Note that parenthesis have a bit of priority. This means that Lua, when it encounters a parenthesis, first evaluates everything in the parenthesis before proceeding with evaluating the rest of the boolean statement. This means that you can have multiple short-circuiting effects and nested pseudo-ternary.
Here is an example...
print(1 and (false or 2) or 0) --> 2 -- 1 is true, but then we encounter a parenthesis. -- Let's evaluate it. -- false is false, so we look at the next statement which is just 2. -- So, our parenthesis returns 2. -- Our statement is simplified to... -- print(1 and 2 or 0) -- Since 2 is the last statement in the combo of ands, we will return 2.
Working with a function call is similar to working with parenthesis. First, you will evaluate what is in the function when you encounter it, similarly to how you would evaluate what is in a parenthesis. Then, you will proceed with the resulting value as you would regularly.
Here is an example...
function a() return 2 end print(false or a() and 3) --> 3 -- Notice how false is false, so we go to the next statement. -- We encountered a function call a() so we will evaluate it. -- a() returns 2 so our statement is simplified to... -- print(false or 2 and 3) -- We proceed regularly since 2 is true, and return 3.