Lua has two indefinite looping commands: while and repeat, a definite loop command, for, and one decision command, if. The for command has two forms, numeric and generic, and this latter form is what we will concentrate on, as it is likely different from other coding experience you have had.
while and repeat LoopsBoth of these commands repeat a block of code based on a control expression. The control expression is any expression that results in a value of either true or false. For example,
i < 10
current_zone == selected_zone
result ~= nil
are three valid control expressions.
The while command continues to repeat as long as the control expression is true. It always tests the control expression before executing the block of code to repeat. Thus, in the following example, the block of code is never executed.
i = 10
while i < 10 do
print("In the loop")
i = i + 1
end
The repeat command, however, only executes while the control expression is false. It checks the control expression after the block of code executes. Thus, with a repeat command, the block of code is always executed at least once! The following example demonstrates that you must be careful with a repeat command.
i = -1
repeat
print("i is positive")
i = i - 1
until i < 1
It is often useful to be able to break out of a loop early. The break command will do that—leave any loop (while, repeat, for) early. Keep in mind, however, that break must be the last command in a block of code. Usually this is not a problem. In the following example, the if command introduces a new block, and the break command is the only (and therefore, last) command in this block.
i = 10
while i > 0 do
if i == 3 then break end
print(i)
i = i - 1
end
Sometimes we might want to use break without it being the action of an if command. This is often the case when we are debugging code. We can do this by using the Lua keywords do and end to make a block. In a latter lesson, we'll see why creating arbitrary blocks can be useful for other reasons. For now, the following example shows how we can use break in arbitrary locations.
i = 10
while i > 0 do
print(i)
do
break
end
i = i - 1
end
A couple of points to note:
The control expression does not need to be enclosed in parenthesis, although it can be. So, both of the following are valid:
while (i < 10) do
while i < 10 do
nil. But, nil cannot be used in arithmetic and other expressions. So the following will give you an error:
while brand_new_variable < 10 do
while loops; true for repeat loops). The following example will require the use of Ctl-Alt-Delete to zap the Script Manager program:
while i < 10 do
print(i)
end
if StatementLua provides one command for executing one of several different blocks of code based on a condition. The if command can conditionally execute a block of commands:
if current_selection == 10 then
print("The tenth item was selected.")
end
Or, it can be used to choose between one of two different blocks:
if current_selection == 10 then
print("The tenth item was selected.")
else
print("Some other item was selected.")
end
Or, it can be used to select one of several different blocks:
if current_selection == 10 then
print("The tenth item is selected.")
elseif current_selection < 5 then
print("An item before the fifth was selected.")
elseif current_select < 10 then
print("An item before the tenth and after the fourth was selected.")
else
print("Some other item was selected.")
end
A couple of points to note:
if command.then is always required. Further, all if commands must use the end keyword.for LoopAs was mentioned, Lua supports two versions of the forstatement. The first version specifies an index variable and a range of value for the index. Each time through the loop, the index variable is assigned the next value in the range. When the index variable has been assigned all values in the range, the loop terminates. Thus, to print the numbers one through ten, we can do as follows:
for i = 1,10 do
print(i)
end
We can add an optional third parameter, the step value. The step defaults to one, but by setting it to another value, we can have the index variable count down, or skip, or both. The next example counts even numbers, backwards from 20.
for i = 20,0,-2 do
print(i)
end
Keep in mind that the range is inclusive. Thus, the index variable will assume the first listed value the first time through the loop. It will assume the last listed value for the last loop iteration, except possibly if the step value causes the upper limit to be skipped. See the following example where the last value the index variable assumes is 19.
for i = 1,20,2 do
print(i)
end
for LoopThe other form of for statement is the so-called generic for. In this version, one or two index variables are assigned values each time through the loop. The values come from a table specified in the statement. The first index variable is assigned successive keys from the table and the second index variable receives the corresponding values. Suppose we have a grocery list stored in a table, we can use the generic for to print it out as follows:
groceries = { 'apples', 'ice cream', 'brussel sprouts', 'paper towels' }
for k, v in groceries do
print(k,v)
end
The output is as follows:
1, apples
2, ice cream
3, brussel sprouts
4, paper towels
The numbers are the table indices from the table groceries. Since these indices are all integers, we could also access our grocery items as follows:
for i = 1,4 do
print(i, groceries[i])
end
But this second method for accessing table information is not always possible. Suppose we change our grocery list so that the indices are the items to purchase and the values stored in the table are the quantities to buy. (We'll see in the next lesson that there is an easier way to specify the table.)
groceries = {}
groceries['apples'] = '5 pounds'
groceries['ice cream'] = '2 quarts'
groceries['brussel sprouts'] = '1 bushel'
groceries['paper towels'] = '1 roll'
A numeric for will not work because none of the data in the table is stored at numeric indices. But the generic for will let us access the information:
for item, amount in groceries do
print(item, amount)
end
This yields the following output:
paper towels, 1 roll
brussel sprouts, 1 bushel
apples, 5 pounds
ice cream, 2 quarts
Was the order the data was printed surprising? Another important point to keep in mind is that there is no guarantee for the order items are accessed in a generic for. If we want the information printed in a particular order, we will have to resort to a slightly more complicated approach. We will examine this in the exercises.
Finally, this is a good point to mention a common Lua idiom: the underscore variable. In Lua, not only is the underscore a valid character for variable names (just like many other langauges), but it is also a valid variable name all by itself. Common Lua usage is to use the underscore variable whenever we are explicitly ignoring information. Let's return to our grocery list example. Suppose we are only interested in printing out the items to buy and not their quantities. We could do this as follows:
for item, amount in groceries do
print(item)
end
That is, we just choose not to print out the amount. However, it is generally good practice to follow the Lua idiom to be explicit that we are ignoring the amount. We can do so as follows:
for item, _ in groceries do
print(item)
end
There are a few errors in the Ecotect documetation relating to the for loop. They are listed below:
In the Control Structures section,
pairs. This function is not implemented in Ecotect's version of Lua.In the section titled The For Loop,
pairs and ipairs are not implemented.next is implemented as described. However, the following example using for does not work.io.lines and file:lines are not implemented. In fact, these are features from Lua 5.