This is the seventh entry in my Lua Tutorial series. See here for an introduction for this series, or here for our previous entry covering using tables. Please see here for our first entry.
Introduction
In our last entry for loops and logic, we covered the basics of for, while, and repeat…until loops, some basic conditions, and the basics of if statements. We’re going to cover some ways to stack conditions and some more logical control over our programs. We can nest statements where necessary, but this isn’t always clean or ideal to do.
Boolean Statements
Lua includes two basic operators to help you stack Boolean comparisons as well as parentheses and similar operations which follow PEMDAS. The two operators are and and or. There are other operations which can be built out of these two, but these are not extremely important at this level. These two operations basically come after all of the PEMDAS operations with and coming taking precedence over or (see Programming in Lua’s Precedence section for more information).
and Statement
The first operation, A and B, basically translates to both A and B need to be true for the statement to be true. In this example, A and B can be anything which returns a Boolean value or similar in Lua. See below for some logical examples:
Statement | A | B | Result |
---|---|---|---|
true and false | true | false | false |
true and true | true | true | true |
false and false | false | false | false |
1 and 2 | true | true | true |
1 and nil | true | false | false |
2 > 1 and not false | true | true | true |
or Statement
The second item, A or B, basically translates to if A or B are true, the entire statement is true, and if A and B are both false, the entire statement is false. In Lua, A or B, does not boil down to the same basic statement of A or B in English. “A or B” in English basically boils down to either A or B, but most programming languages treat that as an xor which means an exclusive or. The following table covers some examples of Lua’s or statement:
Statement | A | B | Result |
---|---|---|---|
true or false | true | false | true |
true or true | true | true | true |
false or false | false | false | false |
1 or 2 | true | true | true |
1 and nil | true | false | true |
2 > 1 and false | true | false | true |
This can further be reduced down to the following table as a comparison:
and Statement | and Results | or Statement | or Results |
---|---|---|---|
true and true | true | true or true | true |
true and false | false | true or false | true |
false and true | false | false or true | true |
false and false | false | false or false | false |
not Statement
in addition to and and or, we also have not which basically turns true to false and false to true. These types of inversions are extremely useful. See the chart below for a set of not constructions:
and Statement | and Results | or Statement | or Results |
---|---|---|---|
not( true and true ) | false | not( true or true ) | false |
not( true and false ) | true | not( true or false ) | false |
not( false and false ) | true | not( false or false ) | true |
Examples
These various constructions can be used to remove some of the need to nest if statements and similar. We can change:
a = true
b = true
c = true
if a == true then
if b == true then
if c == true then
print( "a, b, and c are true" )
end
end
end
Into:
a = true
b = true
c = true
if a == true and b == true and c == true then
print( "a, b, and c are true" )
end
This could be further shortened into:
a = true
b = true
c = true
if a and b and c then
print( "a, b, and c are true" )
end
Boolean Logic in Loops
These shortenings can carry over to while and repeat…until loops as well. This does not appear to be immediately useful, but can be extremely useful. We can see an example below where we fill in some example functions:
a = status()
b = other_status()
while a and b do
operation()
a = status()
b = other_status()
end
While this example won’t do anything if we try to run it without filling in each function, we can see the value. Basically, you can carry over whatever Boolean operations to whatever conditional statements you use in Lua. Functions will be covered in short order, but these functions would just run an operation with no parameters, then set a to the results of status and b to the results of other_status without any parameters for either. Only for loops are an exception to this kind of structure (specifically because nothing should change their control variables), but they have their own variants which make up for this shortcoming.
Short Circuit Evaluation
One thing which has not yet been introduced is short circuit evaluation. Lua is like many programming languages in that it only evaluates operands when necessary. This means that if we run something like:
a = false
b = true
if a and b then
print( "a and be are both true!" )
end
Then, our b is never actually evaluated. This is useful in that sometimes you can omit certain error handling if a piece of data has to be true to evaluate the second piece of data. For instance, you might need to use some error handling for something like:
a = get_data()
b = nil
if a ~= nil then b = special_function( a ) end
if a ~= nil and b ~= nil then print( a .. b ) end
We can basically shorten this to:
a = get_data()
b = nil
if a ~= nil then b = special_function( a ) end
if a ~= nil then print( a .. b ) end
Because we will never be able to run b ~= nil since we suppose our b depends on a. In our example, special_function( a ) is a little different than our other functions. This basically takes special_function and passes a to it as a parameter in the function. This is not important right now except to express that b requires a in order to actually be populated with any data. The b ~= nil will never be evaluated unless a is not nil. If b did not depend on a, then we could run into the issue of trying to concatenate a nil value to a string which would cause Lua to crash. In fairness, it still may be worth writing it the first way just to reduce bugs down the line if the function can return a nil for b depending on the function, but for the logic, it is not necessary with what we laid out.
Summary
This article is a bit different so I am not going to break out a separate summary section with a breakdown of the earlier examples since this content is a bit denser than earlier episodes. These logical statements are pretty much in line with most other programming languages, but they are still worth being familiar with. There are some idioms which will be covered in the future involving some logical evaluations which can help simplify certain problems, but for the time being, it is best to stick with the basics.