Let’s Learn Lua Loops and Logic (Part 2)

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:

StatementABResult
true and falsetruefalsefalse
true and truetruetruetrue
false and falsefalsefalsefalse
1 and 2truetruetrue
1 and niltruefalsefalse
2 > 1 and not falsetruetruetrue

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:

StatementABResult
true or falsetruefalsetrue
true or truetruetruetrue
false or falsefalsefalsefalse
1 or 2truetruetrue
1 and niltruefalsetrue
2 > 1 and falsetruefalsetrue

This can further be reduced down to the following table as a comparison:

and Statementand Resultsor Statementor Results
true and truetruetrue or truetrue
true and falsefalsetrue or falsetrue
false and truefalsefalse or truetrue
false and falsefalsefalse or falsefalse

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 Statementand Resultsor Statementor Results
not( true and true )falsenot( true or true )false
not( true and false )truenot( true or false )false
not( false and false )truenot( 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.