unknown_document

We couldn't find that page... Were you looking for one of these?


Lua's Numeric For Loop
As we learned in the previous sections, the while and repeat control structures allow a program to loop over a block of code until a specified condition is met. These are sometimes called "condition-controlled" loops. Another common loop is called a "count-controlled" loop, in which the loop iterates a specified number of times. In Lua, this type of loop is called the "Numeric For Loop". The general pattern for the numeric for loop is: for [ var ] = [ start ], [ stop ], [ step = 1 ] do -- loop body -- repeat for each specified iteration end where var is an arbitrary variable name that is locally-scoped to the loop body, and the start , stop , and (optional) step parameters define "how" the loop will execute. Loop execution can be more easily understood by considering it to proceed in two parts, which we could call initialization and iteration . Initialization When the Lua encounters a for loop , the first thing it does is evaluate each of the start , stop , and (optional) step expressions, which are used to generate a sequence of numbers that will define: How many times the loop body will execute, and What values will be assigned to var prior to each iteration of the loop. Each number in the generated sequence will be assigned to var , one by one, until the sequence is exhausted. The first number in the loop is the value assigned to start , then the second number is start + step , then the third in start + 2 * step , and so on: var = start var = start + 1 * step -- first iteration var = start + 2 * step -- second iteration var = start + 3 * step -- third iteration ... var = start + n * step -- nth iteration This list continues for n steps, until start + n * step >= stop . When step is not specified, it is assigned a default value of 1. Iteration Now that we have initialized the loop, we can move to the iteration step. In this step, the loop body is execute once for each value of var in the "iteration list". The main point of this step is to define the loop body so that it performs the correct operations given each value of var . Examples Let's take a look at a few examples: Example 1 In the first example, let's consider a simple loop that counts from 0 to 5: for x = 0 , 5 do print ( "x = " .. x ) end When executed, this loop generates the following output: x = 0 x = 1 x = 2 x = 3 x = 4 x = 5 Example 2 As a second example, let's pick another simple with a step value of 2: for x = 0 , 10 , 2 do print ( "x = " .. x ) end This loop behaves similarly to the previous example, except for the value assigned the x . x = 0 x = 2 x = 4 x = 6 x = 8 x = 10 Example 3 Finally, as a final example, let's look at a slightly more complicated case that requires the stop and step parameters to be evaluated prior to generating the sequence of values to iterate over: for x = 0 , 2 * 3.14 , 3.14 / 2 do print ( "x = " .. x ) end Although the mechanics of generating the loop values is slightly different, loop operation remains basically the same: x = 0.0 x = 1.57 x = 3.14 x = 4.71 x = 6.28 Early Termination Although the basic operation of the numeric for loop is to repeat the loop body for a pre-determined number of iteration, it is possible to terminate the loop early if needed. This is generally done using break , although a loop inside of a function can also terminate early when a return is encountered: break In order to demonstrate break we will use the following shamefully-contrived example. In this example, the loop parameters call for iterating the loop 6 times, but the loop body contains code to terminate the loop early if a specific condition is encountered: for x = 0 , 5 do if x == 3 then break end print ( "x = " .. x ) end When this loop executes, it generates the following output: x = 0 x = 1 x = 2 This is obviously a contrived example, but shows a pattern that can be helpful in cases where the loop parameters define the maximum number of times that the loop will iterate, while containing additional logic enforcing condition under which the loop should terminate early. return As with the "condition-controlled" loops we look at previously, the return statement can also be used terminate a "numeric for" loop early when operating inside a function. The following code demonstrates this with a similar implementation: local function count () for x = 0 , 5 do if x == 3 then return end print ( "x = " .. x ) end end count () which produces the following output: x = 0 x = 1 x = 2
Lua's Generic For Loop
The final loop that we will look is a Lua' implementation of the "collection-controlled" loop, the Generic For loop. The Generic For executes its loop body one time for each value generated by an "iterator function", which is a function that (generally) take a collection such as a list-like table as input, and returns an iterator over the values in the collection. Lua provides two built-in iterator functions, pairs and ipairs . Let's take a look at them: pairs The general pattern for constructing a generic for loops using pairs is: for [ key ], [ value ] in pairs ([ table ]) do -- loop body -- repeat for each specified iteration end We provide examples and more information about using pairs in our section about iterating lists . ipairs Lua's second built-in iterator function is ipairs , which is similar to pairs except it returns an "index" with each value of returned. This will become more clear in a moment. The general pattern for constructing a generic for loop using ipairs is: for [ idx ], [ value ] in ipairs ([ table ]) do -- loop body -- repeat for each specified iteration end where idx is an "index", or "loop-counter", that starts at 1 and increases by 1 for each iteration of the loop, and value is a value from the collection. Let's look at an example of how this works: We provide examples and more information about using ipairs in our section about iterating lists . Early Termination Just like the [numeric for] loop, generic for loops can terminate early, using break or, when inside a function , return .
Using And & Or for Control Flow
In the Logical Operators section we learned how the and and or operators can be used to implement logic in conditional expressions, such as those used to control flow in the if-then statements we discussed in the previous section. It turns out that the and and or operators are implemented similarly to if-then statements, which allows them to provide simple and convenient control flow in some common situations. Default Value There are many situations where we want to assign a value to a variable if one exists, then fall back to a default value if needed. This can be implemented as a simple if-then statement like this: local function might_return_nil () return nil end local x = might_return_nil () if x == nil then x = "default" end print ( x ) -- default There is nothing wrong with this code, but in some cases the or operator can be used to create equivalent functionality that is more compact and easier to read. Recall that the or operator returns the first truthy value it encounters, or the last falsy value when all values are falsy . This provides a convenient method of implementing the previous example in a somewhat more concise manner: local function might_return_nil () return nil end local x = might_return_nil () or "default" print ( x ) -- default One of the nice aspects about this is that the code reads like common english: assign either the first value or the second value. Priority There are also some situations where a variable could be assigned one of several values, depending upon some application-dependent prioritization. This could be implemented using an if-then-else statement as follows: local function lower_priority () return "lower" end local function medium_priority () return "medium" end local function high_priority () return "high" end local x if high_priority () then x = high_priority () elseif medium_priority () then x = medium_priority () else x = lower_priority () end print ( x ) -- high Suppose that each of the functions returns either a truthy value or a falsy value. In this example we check each prioritization, from highest to lowest, to determine what value should be assigned to x . Recall that the and operator returns the first non- truthy value, or the last truthy value if all values are truthy . This behavior can be leveraged to provide a more compact solution: local function lower_priority () return "lower" end local function medium_priority () return "medium" end local function high_priority () return "high" end local x = lower_priority () and medium_priority () and high_priority () print ( x ) -- high Although this is much more compact than the previous example, the downside is that it doesn't read like common english, which can make it difficult to read. Still, once this pattern is understood it can be a simple, concise means of applying prioritization.
Control Structures
Lua implements several of the basic control structures that might be expected in a programming language. Here is a quick summary of the available options, then we will get into the details in the coming sections: Control Type Structure Conditional If-Then Condition-controlled Loop While Condition-controlled Loop Repeat Count-controlled Loop Numeric For Collection-controlled Loop Generic For
If Then Control Flow in Lua
Conditional statements control program flow by evaluating an expression then proceeding to one or more different "paths" depending on the result. Lua implements conditional statements with the if-then statement, which supports several variations. If-Then The most simple conditional statement contains a single boolean condition that directs program flow to a branch if that condition evaluates to true . if-then statements in Lua follow the pattern: if [ boolean expression ] then -- execute when boolean expression is true end The following is a simple example of the if-then statement: local x = 2 local y = 3 local result if x > y then result = x + y end print ( result ) -- nil It this example the values of the x and y variables are compared and, because x is not greater than y , the conditional branch is not executed, and result is not assigned a value. If-Then-Else In the previous example we created a block of code that is only executed if a specific condition exists. Sometimes we need a bit more control over program flow, and want program flow to take one of two paths, depending on the conditional. For this, Lua has the if-then-else statement, which follows the pattern: if [ boolean expression ] then -- execute when boolean expression is true else -- execute when boolean expression is false end Let's look at a simple example: local x = 2 local y = 3 local result if x > y then result = x + y else result = 5 end print ( result ) -- 5 If-Then-Elseif-Else if [ boolean expression # 1 ] then -- execute when boolean expression #1 is true elseif [ boolean expression # 2 ] then -- execute when boolean expression #2 is true elseif [ boolean expression # n ] then -- execute when boolean expression #n is true else -- optional -- execute when all boolean expressions are false end The expression can include any number of elseif clauses, allowing program flow to take any number of alternate paths. Note that the else clause is optional. When included this branch will execute only of all other conditionals are false . Let's extend our example to include a second conditional statement: local x = 2 local y = 3 local result if x > y then result = x + y elseif x < y then result = 10 else result = 5 end print ( result ) -- 10 Now that we have seen how if-then statements work, the next section will take a quick look at using the and and or to perform simple conditional statements.
Lua's While Loop
The While Loop is a "condition-controlled" loop, which executes a block of code 0 or more times, stopping when the controlling condition is true . While loops follow the pattern: while [ boolean expression ] do -- loop body -- repeat as long as boolean expression is true end As a simple example, let's sum up all numbers from 0 to 4: local x = 0 local result = 0 while x < 5 do result = result + x x = x + 1 end print ( result ) -- 10 The break statement can be used to terminate a while loop early. The following is equivalent to the previous example. local x = 0 local result = 0 while true do result = result + x x = x + 1 if x >= 5 then break end end print ( result ) -- 10 Note that in this case we used a boolean expression that is simply true . This is a common practice in many situations, but requires a bit of care in order to prevent infinite loops . We should point out that when a While Loop is contained within a function, the loop can also terminate when it encounters a return statement: local function sum () local x = 0 local result = 0 while true do result = result + x x = x + 1 if x >= 5 then return result end end end print ( sum ()) -- 10
Lua's Repeat Loop
Like the While Loop , the Repeat Loop is a "condition-controlled" loop. Unlike the While Loop , the Repeat Loop guarantees that the loop body is executed at least one time, then stops when the controlling condition is true . Repeat loops follow the pattern: repeat -- loop body -- repeat as long as boolean expression is true until [ boolean expression ] As a simple example, let's sum up all numbers from 0 to 4 using a repeat loop : local x = 0 local result = 0 repeat result = result + x x = x + 1 until x >= 5 print ( result ) -- 10 The break statement can be used to terminate a repeat loop early, just like a while loop . The following is equivalent to the previous example. local x = 0 local result = 0 repeat result = result + x x = x + 1 if x >= 5 then break end until false print ( result ) -- 10 Note that in this case we set the boolean expression to false , so that it continues to execute until the break is encountered. As while the while loop , care must be taken to prevent infinite loops . Finally, let's implement the final example from the while loop section using a repeat loop , showing that the repeat loop also terminates when a return statement is encountered: local function sum () local x = 0 local result = 0 repeat result = result + x x = x + 1 if x >= 5 then return result end until false end print ( sum ()) -- 10
Lua
Lua is a lightweight, cross-platform, high-level programming language that has become increasingly-popular as an embedded scripting language. Lua is often praised as a clean, simple, easy to learn scripting language that is applicable to a wide range of tasks. Today Lua can be found in a wide range of applications ranging from wezterm to xplr and neovim . Let's get started.
Lua's Arithmetic Operators
Basics Let's first take a look at the basics, addition , subtraction , multiplication , and division . These work as one would expect: local x = 2 local y = 3 print ( x + y ) -- 5 print ( x - y ) -- -1 print ( x * y ) -- 6 print ( x / y ) -- 0.66666666666667 Negation Whereas almost all languages allow a value to be negated by multiplying it by -1 to negative it, Lua additionally allows a value to be negated by simply prefixing it with - . local x = 2 local y = 3 print ( - x ) -- -2 print ( - y ) -- -3 print ( x + - y ) -- -1 Note that negation occurs independently of other operators, as shown in the last case. We will learn more about this in a moment when we discuss precedence . Exponentiation Lua supports exponentiation with the ^ operator: local x = 2 local y = 3 print ( x ^ y ) -- 8.0 print ( y ^ - x ) -- 0.11111111111111 Modulus Like many programming languages modular arithmetic in Lua uses the % operator. While the topic of modular arithmetic is well outside the scope of learning about Lua, this is a useful but often misunderstood function, so let's give it a quick review. To calculate a % b, one first finds the largest integer k such that multiplying k by b is less than a , then the result is the difference or remainder, a - kb . local x = 2 local y = 3 print ( x % y ) -- 2 print ( y % x ) -- 1 In the first example y is greater than x , so the remainder is simply x . In the second example the largest integer k is 1 , so that the remainder is 3-2=1 . Bitwise Lua also supports the basic bitwise operations. While bitwise operations are very important in computing, they are used in a fairly narrow range of applications so we won't spend too much time on them other than to show which operations are supported and a simple example of how they work: local x = 2 local y = 3 print ( x & y ) -- 2 print ( x | y ) -- 3 print ( x ~ y ) -- 1 You can learn more about bitwise operations here .
Lua's Number Type
The first data type we will look at is number . Numbers are used to represent quantities or amounts, and are also used in some control structures and to retrieve values from tables . Whereas many languages differentiate between integer and floating point numbers , Lua treats all numbers as double-precision floating-point numbers . Lua is quite flexible about how numbers are formatted, accepts most common floating-point formats, and will even automatically convert strings to numbers when performing arithmetic operations : -- integer print ( 123 ) -- 123 -- floating point print ( 1.23 ) -- 1.23 print ( 0.0456 ) -- 0.0456 -- exponential print ( 0.123e+3 ) -- 123.0 print ( 123e-3 ) -- 0.123 print ( 4.56E2 ) -- 456.0 -- hexadecimal print ( 0x00 ) -- 0 print ( 0x7B ) -- 123 print ( 0xff ) -- 255 --strings print ( "120" + 3 ) -- 123 print ( "0x78" + 3 ) -- 123 We will see a bit more about working with numbers in the arithmetic operations section.