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

This is the fourth entry in my Lua Tutorial series. See here for an introduction for this series, or here for our previous entry covering variables.

We covered some of the basics of variables last time and some basic input and output, now we’re going to move onto some control logic and looping. These are the building blocks of any real program. Once we cover some of the logic and basics of looping, we’re going to move on to tables and similar before moving onto further control structures. The goal here is to get some of the basic pieces to start making actual programs before going back and fleshing these concepts out further. I am also going to include some exercises down the road to put some of the previous tutorials together and help cement these concepts.

Lua has several kinds of loops including: for, while, and repeat … until. These three types of loops are found in most programming languages, but the repeat … until is typically called do … while or something similar. Lua also has control logic with the standard if … then … elseif … else style control. We’re going to start with the loops, move onto if statements, then add some details to both. The goal is to scaffold from easiest to hardest. One thing to note as well (which will be repeated below) is that many of the parentheses are optional. I have included them to make it easier to parse out what is doing what in each piece, but they will be removed in later lessons.

for loops:

for loops are basically the most fundamental kind of loop in general. There are several variants we will cover later, but the basic usage of the standard for loop is as follows:

for [initial value], [limit], [increment value] do
	[stuff]
end

Two actual examples of this would be:

for i = 0, 10, 1 do
	print( "i = " .. i )
end

Remember that .. is the string concatenation operator as mentioned in the last lesson. In Lua, basically all scalars have a string representation so we don’t need to cast this like in some languages.

for j = 10, 0, -2 do
	print( "j = " .. j )
end

The first example results in:

i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
i = 10

And the second results in:

j = 10
j = 8
j = 6
j = 4
j = 2
j = 0

Basically, we set our initial value to set a variable to whatever we want to start with, then we set a limit for this in the second value, then we finalize it with how to increment. There is another form of the for loop which we will cover later with tables.

Comparisons:

Before we move on to our while loops, we are going to cover some types of comparisons in Lua. We will go over these conditions at length more later with if statements and even further in the next few lessons. The most fundamental condition is a comparison of equality. Does A equal B? We saw before that we could set A = [value], but this actually sets our variable, how can we tell Lua that we just want to check? All it takes is an extra = sign, so, A == B. We have a whole host of operators we can put below.

OperatorExampleMeaning
==A == BCompare if the value of A is equal to the value of B
~=A ~= BCompare if the value of A is NOT equal to the value of B
>A > BCompare if A is larger than B
>=A >= BCompare if A is equal to or larger than B
<A < BCompare if A is less than B
<=A <= BCompare if A is less than or equal to B

Don’t worry about memorizing these all yet. We will have a lesson on Boolean Logic and comparisons in Lua later. Just familiarize yourself with these in a simple way since there are some caveats and tricks for different types of data.

while loops:

while loops are another important type of loop. These loops are a bit more flexible than for loops in certain regards, but have certain caveats. These loops can be let loose to run forever (or more realistically until the process crashes) so you have to be careful! while loops look like follows:

while ( [condition] ) do
	[stuff]
end

An easy example of a while loop would be:

i = 0
while ( i < 10 ) do
	print( "i = " .. i )
	i = i + 1
end

This prints exactly the same thing as our first for example but takes some extra work compared to a for loop, so why would we use it? The answer is simple, while loops excel at other kind of conditional checks you couldn’t do with a for loop. For example:

answer = "5"
useranswer = ""

while ( useranswer ~= answer ) do
	io.write( "What is 3 + 2? " )
	useranswer = io.read()
end

This will continue to ask the user what 3 + 2 is over and over until they respond with 5. Notice how we set our useranswer = “”, there is a rhyme and reason for that since we wanted to initialize the variable. There is a much cleaner way to do this, but that will be covered with the next type of loop.

repeat … until loops:

repeat … until loops are basically the same as while loops, except they will always run at least once through. The condition also goes at the end of the loop instead of at the top. They look like follows:

repeat
	[stuff]	
until ( [condition] )

I mentioned in the previous section that you could change the example while loop to be much cleaner, so let’s see what it looks like:

answer = "5"

repeat
	io.write( "What is 3 + 2? " )
	useranswer = io.read()
until ( useranswer == answer )

This code does exactly the same as the previous example in the while section, but we don’t have to worry about the variable until we are in the loop so it can look a lot cleaner. The big difference is that this loop will always run at least once while a while loop will not necessarily have to run. Another difference is when the condition is computed. If you have raw data going into the loop, a while may be better as you can compare the data before even running, while with a repeat … until, you will run and may pollute the previous data.

Now that we’ve covered the basics of loops, let’s use our conditions we learned earlier and learn about if statements.

Basic if statements:

if statements are integral to program flow. They allow you to check a condition and either act on it or not. if statements can be expanded by the use of elseif and else which we will get to in a little bit. The most basic if statement looks like:

if ( [condition] ) then
	[stuff]
end

The condition can be basically anything which returns a Boolean (more on this later), and at this point, more specifically the conditions we mentioned above. The conditions can be just like the while loop or repeat … until loop as well. For a quick example:

io.write( "What's your name? " )
name = io.read()

if ( name == "Scott" ) then
	print( "Hi Scott!" )
end

If you run this, you get something like follows: What's your name? John or What's your name? Scott
Hi Scott!

That can help for certain conditions, but what if we want to do something different for John or similar? We can stack if statements to accomplish this, but there is a better way. Both else and elseif allow us to expand the flexibility of our if statements. Here’s how this works out roughly:

if ( [condition A] ) then
	[stuff]
elseif ( [condition B] ) then
	[stuff]
elseif ( [condition C] ) then
	[stuff]
…
else
	[stuff]
end

We can use as many, or as few elseif statements with our if statement as we want, including even just skipping them altogether. Let’s say we want to do something like our program earlier, but we want to take into account John and Scott both, we could do the following:

io.write( "What's your name? " )
name = io.read()

if ( name == "Scott" ) then
	print( "Hi Scott!" )
elseif ( name == "John" ) then
	print( "What's up John?" )
end

That’s cool, but what if we have an entire group of people and we don’t want to leave them out as well? That’s where else really comes in handy like below:

io.write( "What's your name? " )
name = io.read()

if ( name == "Scott" ) then
	print( "Hi Scott!" )
elseif ( name == "John" ) then
	print( "What's up John?" )
else
	print( "Hey there, " .. name )
end

Putting it all together

Now let’s try to put these things together and work in some new logic.

for j = 0, 20, 1 do
	io.write( j )
	if ( j % 5 == 0 ) then
		io.write( " is divisible by 5!" )
	end
	io.write( "\n" )
end

This should result in the following:

1
2
3
4
5 is divisible by 5!
6
7
8
9
10 is divisible by 5!
11
12
13
14
15 is divisible by 5!
16
17
18
19
20 is divisible by 5!

Our new code does a couple of cool things we hadn’t seen up until now. One, we nested a conditional if into our loop, and two, we combined some math with a comparison in that if statement. Our if statement basically boils down to if j modulus 5 is 0, then. Since we didn’t assign the results to anything, they basically disappear after the loop and don’t affect anything else. We also see that there is a precedence for operations as well. The standard mathematical order of operations is basically followed, and then we go into comparisons which have a similar order lower in the hierarchy. Just like our old friend PEMDAS from basic math, we can also use parentheses to force a different order. This will be detailed far more in our section on Boolean logic and other conditions in Lua. Another thing to note is that a lot of the parentheses used above are not, strictly speaking, necessary. For example, we could write code as follows:

j = 0
while j <= 20 do
	io.write( j )
	if j % 5 == 0 then
		io.write( " is divisible by 5!" )
	end
	io.write( "\n" )
	j = j + 1
end