Looping Constructs

This section describes the loop expressions in the Curl® language. A loop expression evaluates the enclosed code a number of times. The number of times that the enclosed code is evaluated depends on the type of loop and the control conditions for that loop. The Curl language includes the following loop expressions:

while Expression

Summary:
  • Repeatedly execute a code block while a Boolean expression evaluates to true.
The while expression allows you to repeatedly execute code when a Boolean expression evaluates to true. Before each iteration of the code, the Curl® Runtime Environment (RTE) evaluates the Boolean expression. If it is true, the enclosed code is executed. If it is false, the runtime does not execute the code and moves to the end of the while expression. The while expression has the following syntax:
Syntax:{while [tag=tag-name,] condition do
body1
[next body2] ... }
where:
tag-nameis a unique tag name for this loop. The tag name is optional. Specify a tag name if you want to use the continue or break expressions with tag names in code. Specify a valid Curl language identifier. See continue and break for more information.
conditionis a Boolean expression.
body1consists of one or more Curl language expressions.
next body2is an optional next clause. Specify one or more to serve as targets for continue statements. See continue.
When the runtime encounters a while expression, it evaluates condition. If condition is true, the runtime executes code and moves back to the beginning of the while expression (repeating the process). If condition is false, the runtime does not execute code and moves to the end of the while expression.
A while expression does not return a value. The runtime evaluates the conditions and evaluates the statements and expressions in the enclosed code block an appropriate number of times.
An example of a while expression follows:

Example: Using the while Expression
{value
    || Define and initialize an integer variable: start=1.
    || Define a horizontal box variable called message to store
    || and display a string.
    let start:int=1
    let message:HBox={HBox}

    || While start is less than 10 do the following:
    ||  - Place the value of start in message.
    ||  - Increment start (add 1 to its value).
    {while start < 10 do
        {message.add start}
        set start = start + 1
    }

    || Display the contents of message.
    message
}
You can use branching expressions within loop expressions to change program flow. See continue and break for more information.

until Expression

Summary:
  • Repeatedly execute a code block until a Boolean expression evaluates to true.
The until expression allows you to repeatedly execute code until a Boolean expression evaluates to true (in other words, the runtime repeatedly executes the code while a Boolean expression evaluates to false). Before each iteration of the code, the runtime evaluates the Boolean expression. If it is false, the enclosed code is executed. If it is true, the runtime does not execute the code and moves to the end of the until expression. The until expression has the following syntax:
Syntax:{until [tag=tag-name,] condition do
body1
[next body2] ...}
where:
tag-nameis a unique tag name for this loop. The tag name is optional. Specify a tag name if you want to use the continue or break expressions with tag names in code. Specify a valid Curl language identifier. See continue and break for more information.
conditionis a Boolean expression.
bodyconsists of one or more Curl language expressions.
next body2is an optional next clause. Specify one or more to serve as targets for continue statements. See continue.
When the runtime encounters an until expression, it evaluates condition. If condition is false, the runtime executes code and moves back to the beginning of the until expression (repeating the process). If condition is true, the runtime does not execute code and moves to the end of the until expression.
An until expression does not return a value. The runtime evaluates the condition and evaluates the statements and expressions in the enclosed code block an appropriate number of times.
An example of an until expression follows:

Example: Using the until Expression
{value
    || Define and initialize an integer variable: start=1.
    || Define a horizontal box variable called message to store
    || and display a string.
    let start:int=1
    let message:HBox={HBox}

    || Until start is equal to 10 do the following:
    ||  - Place the value of start in message.
    ||  - Increment start (add 1 to its value).
    {until start == 10 do
        {message.add start}
        set start = start + 1
    }

    || Display the contents of message.
    message
}
You can use branching expressions within loop expressions to change program flow. See continue and break for more information.

for Expression

Summary:
  • Iterate over a code block a specified number of times.
  • Range loops iterate over code for each value in a range.
  • Container loops iterate over code for each value in a container.
The for expression allows you to iterate over code a specified number of times. Unlike while and until, the number of times the runtime executes the code does not depend on a Boolean expression. The number of iterations depends on a loop variable and its loop settings. There are two categories of for loops:
Note: If you are using a for expression to iterate through the elements of a container, such as an array or a string, make sure to use a container loop. Using a range loop and incrementing the index in such situations can result in suboptimal performance.
A for expression does not return a value. The runtime evaluates the condition and evaluates the statements and expressions in the enclosed code block an appropriate number of times. However, the for expression itself does not return anything.
You can use branching expressions within loop expressions to change program flow. See continue and break for more information.

Range Loops

Summary:
  • You define the loop variable, the start of the range, and the end of the range.
  • You can optionally define the step amount.
  • You can change the value of a loop variable from within the loop.
Range loops are so named because the runtime executes the enclosed code for each value in a numeric range. You define the loop variable, the start of the range, and the end of the range. The runtime sets the variable to the start of the range. Each time the code is executed, it increments or decrements the loop variable according to the loop conditions. The runtime repeatedly executes the code, incrementing or decrementing the loop variable after each execution, until the variable reaches the end of the range. You can optionally specify the amount that the runtime increments or decrements the variable each time. This is called the step amount.
The Curl language allows you to change the value of a loop variable from within the loop. This feature allows you to create a for loop that circumvents the normal flow of operation of a for loop. However, you must take care to avoid infinite loops when using this feature.
Although you can change the value of a loop variable from within the loop, you cannot change the loop settings from within the loop. The loop settings are the start of the range, the end of the range, and the step amount. The loop settings are computed once before the first iteration through the loop. They are not recomputed for subsequent iterations.
There are four forms of the range loop:
{for ... to ... step ... do ...}
This form of the for loop performs an iteration of the code for each value of the loop variable between the start of the range and the end of the range, including the value at the end of the range. In other words, this form of the for expression executes the code when the loop variable is less than or equal to the end of the range. This form has the following syntax:
Syntax:{for [tag=tag-name,] variable-name[:type] = start-range to end-range [step step-value] do
body1
[next body2] ... }
where:
tag-nameis a unique tag name for this loop. The tag name is optional. Specify a tag name if you want to use the continue or break expressions with tag names in code. Specify a valid Curl language identifier. See continue and break for more information.
variable-nameis the name of the loop variable. Specify a unique identifier.
typeis the data type of the loop variable. Specifying the data type of the loop variable is optional. If you do not specify the type, the runtime infers the type of start-range and uses that data type for the loop variable.
start-rangeis the start of the range (the initial value of the loop variable).
end-rangeis the end of the range (the final value of the loop variable).
step-valueis the amount that the loop variable is incremented after each iteration. Specifying the step value is optional. If you do not specify the step value, the runtime increments the loop variable by 1 (or 1.0 if you are working with float values) each time. Make sure to specify a positive value. Note that if you specify zero (0), your code enters an infinite loop unless you provide another way to exit the loop.
body1consists of one or more Curl language expressions.
next body2is an optional next clause. Specify one or more to serve as targets for continue statements. See continue.
When the runtime encounters such a for expression, it defines the loop variable and initializes it to start-range. If the loop variable is less than or equal to end-range, code is executed. After executing code, the runtime increments the loop variable. If the loop variable is less than or equal to end-range, code is executed once more. This process of updating the loop variable, checking for loop termination, and running code continues until the loop variable is greater than end-range. For example:

Example: Using the {for ... to ... step ... do ...} Range Loop
{value
    || Define a horizontal box variable called message to store
    || and display a string.
    let message:HBox={HBox}

    || Define x to be an integer.  Initialize x to 0.
    || Increment x by 1 after each iteration of the
    || loop (default).  For each value of x up to and
    || including 8, do the following:
    ||  - Place the value of x in message.
    {for x:int=0 to 8 do
        {message.add x}
    }

    || Display the contents of message.
    message
}
Here is an example that uses the step clause:

Example: Using the Step Clause with the
{for ... to
... step ... do ...}
Range Loop
{value
    || Define a horizontal box variable called message to store
    || and display a string.
    let message:HBox={HBox}

    || Define x to be an integer.  Initialize x to 0.
    || Increment x by 2 after each iteration of the
    || loop.  For each value of x up to and including
    || 8, do the following:
    ||  - Place the value of x in message.
    {for x:int=0 to 8 step 2 do
        {message.add x}
    }

    || Display the contents of message.
    message
}
Here is an example that changes the value of the loop variable within the loop. In this case, the loop variable is incremented if the subsequent iteration is divisible by three. Remember that the value of the loop variable is also incremented at the end of each iteration of the loop. Therefore, for iterations that manually increment the value of the loop variable, the loop variable is actually incremented twice (thus avoiding the iteration that is divisible by three).

Example: Changing the Value of a Loop Variable
{value
    || Define a horizontal box variable called message to store
    || and display a string.
    let message:HBox={HBox}

    || Define x to be an integer.  Initialize x to 0.
    || For each value of x up to and including 8, do the
    || following:
    ||  - Place the value of x in message.
    ||  - If the next iteration of x (that is x + 1)
    ||    will be divisible by 3, then increment x
    ||    to avoid executing the loop for values of x
    ||    that are divisible by 3 (remember that x
    ||    is also incremented at the end of each
    ||    iteration.)
    {for x:int=0 to 8 do
        {message.add x}
        {if (x + 1) mod 3 == 0 then
            set x = x + 1
        }
    }

    || Display the contents of message.
    message
}
Here is an example that changes the value of a variable that sets the step amount. Remember that the loop settings are bound only before the first iteration through the loop. They are not bound for subsequent iterations. The loop in this example includes an expression that increments the variable that sets the step amount. However, the step amount for each iteration through the loop does not change because it was bound before the first iteration of the loop.

Example: Changing the Value of a Variable That Sets the Step Amount
|| Define a horizontal box variable called message to store
|| and display a string.
{let message:HBox={HBox}}

|| Define a to be a variable that holds the step
|| amount.  Initialize a to the value 1.
{let a:int = 1}

|| Define x to be an integer.  Initialize x to 0.
|| For each value of x up to and including 9, do the
|| following:
||  - Place the value of x in message.
||  - Increment the value of a.
{for x:int=0 to 9 step a do
    {message.add x}
    set a = a + 1
}

|| Display the contents of message.
{value message}

|| Display the value of a.
{value a}
{for ... below ... step ... do ...}
This form of the for loop is like
{for ... to ...
step ... do ...}
, except that it executes the loop for each value up to, but not including, the last value in the range. In other words, this form of the for expression executes the code when the loop variable is less than the end of the range. This form has the same syntax as
for
... to ... step ... do ...
, except that below appears in place of to:
Syntax:{for [tag=tag-name,] variable-name[:type] = start-range below end-range [step step-value] do
code }
For example:

Example: Using the {for ... below ... step ... do ...} Range Loop
{value
    || Define a horizontal box variable called message to store
    || and display a string.
    let message:HBox={HBox}

    || Define x to be an integer.  Initialize x to 0.
    || Increment x by 1 after each iteration of the
    || loop (default).  For each value of x up to 8,
    || do the following:
    ||  - Place the value of x in message.
    {for x:int=0 below 8 do
        {message.add x}
    }

    || Display the contents of message.
    message
}
Here is an example that uses the step clause:

Example: Using the Step Clause with the
{for ... below
... step ... do ...}
Range Loop
{value
    || Define a horizontal box variable called message to store
    || and display a string.
    let message:HBox={HBox}

    || Define x to be an integer.  Initialize x to 0.
    || Increment x by 2 after each iteration of the
    || loop.  For each value of x up to 8, do the
    || following:
    ||  - Place the value of x in message.
    {for x:int=0 below 8 step 2 do
        {message.add x}
    }

    || Display the contents of message.
    message
}
{for ... downto ... step ... do ...}
This form of the for loop is like {for ... to ... step ... do ...}, except that it decrements the loop variable by the step value. In other words, this form of the for expression executes the code when the loop variable is greater than or equal to the end of the range. This form has the same syntax as for ... to ... step ... do ..., except that downto appears in place of to:
Syntax:{for [tag=tag-name,] variable-name[:type] = start-range downto end-range [step step-value] do
code}
When the runtime encounters such a for expression, it defines the loop variable and initializes it to start-range. If the loop variable is greater than or equal to end-range, the runtime executes code. After executing code, it decrements the loop variable. If the loop variable is greater than or equal to end-range, it executes code once more. This process of updating the loop variable, checking for loop termination, and running code continues until the loop variable is less than end-range. For example:

Example: Using the {for ... downto ... step ... do ...} Range Loop
{value
    || Define a horizontal box variable called message to store
    || and display a string.
    let message:HBox={HBox}

    || Define x to be an integer.  Initialize x to 8.
    || Decrement x by 1 after each iteration of the
    || loop (default).  For each value of x down to 0,
    || do the following:
    ||  - Place the value of x in message.
    {for x:int=8 downto 0 do
        {message.add x}
    }

    || Display the contents of message.
    message
}
{for ... above ... step ... do ...}
This form of the for loop is like {for ... downto ... step ... do ...}, except that it decrements the loop variable only while it is greater than the end of the range. This form has the same syntax as for ... downto ... step ... do ..., except that above appears in place of downto:
Syntax:{for [tag=tag-name,] variable-name[:type] = start-range above end-range [step step-value] do
code }
For example:

Example: Using the {for ... above ... step ... do ...} Range Loop
{value
    || Define a horizontal box variable called message to store
    || and display a string.
    let message:HBox={HBox}

    || Define x to be an integer.  Initialize x to 8.
    || Decrement x by 1 after each iteration of the
    || loop (default).  For each value of x down to but
    || not including 0, do the following:
    ||  - Place the value of x in message.
    {for x:int=8 above 0 do
        {message.add x}
    }

    || Display the contents of message.
    message
}

Container Loops

Summary:
  • Iterate over a code block for each value in a container.
  • The body of the loop can access the value of the current element.
  • The body of the loop can access the index or key for the current element.
  • You must reset the iterator before using it again.
Container loops are so named because the runtime executes the enclosed code for each element in a specified container object. You can use a container loop to iterate over any object that has a to-Iterator method. Many classes that are built into the Curl language have to-Iterator methods. These classes include those for strings, arrays, sets, hash tables, argument lists, and rest argument arrays. So, for example, you can use a for loop to execute enclosed code for each character in a string. Or you can use a for loop to execute code for each element in an array. You can also use a container loop on an object that you create, provided you provide a to-Iterator or for-loop-count method; for more information about this, see the API Reference information about for. For information about using a for loop with a rest arguments array, see the Rest Arguments section.
Note: Do not iterate over a container and modify the contents of the container from within the loop. If you do, both the behavior and the results are undefined.
On each iteration of the code, the runtime assigns information about the current element to one or more variables. You can use the information that is placed in these variables within the code in the loop. In particular, you can assign the following to variables:
After you use an iterator in a for loop, you must use Iterator-of.reset to reset the iterator before using it again.
There are three forms of the container loop that correspond to these variable assignments:
{for ... in ... do ...}
In this form of the for container loop, the runtime assigns the value of the element in question to a variable. This form has the following syntax:
Syntax:{for [tag=tag-name,] element-value[:type] in container do
body1
[next body2] ... }
where:
tag-nameis a unique tag name for this loop. The tag name is optional. Specify a tag name if you want to use the continue or break expressions with tag names in the loop. Specify a valid Curl language identifier. For more information, see continue and break.
element-valueis the name of the variable that will contain the value of the element on each iteration. Specify a unique identifier.
typeis the data type of the element variable. Specifying the data type of the variable is optional. If you do not specify the type, data type is inferred from container.
containeris the container object. Valid container objects include strings, arrays, sets, and hash tables.
body1consists of one or more Curl language expressions.
next body2is an optional next clause. Specify one or more to serve as targets for continue statements. See continue.
When the runtime encounters such a for expression, it executes code for each element in container. On each iteration through code, the runtime assigns the value of the element in question to element-value. For example:

Example: Using the {for ... in ... do ...} Container Loop
{value
    || Define a vertical box variable called message to store
    || and display a string.
    let message:VBox={VBox}

    || Define an array a of integers with three values (10,
    || 20, and 30).
    let a:{Array-of int}={{Array-of int} 10, 20, 30}

    || For each value v in the array, place v in
    || message.
    {for v:int in a do
        {message.add v}
    }

    || Display the contents of message.
    message
}
{for key ... in ... do ...}
In this form of the for container loop, the runtime assigns the key for the element in question to a variable. This form has the following syntax:
Syntax:{for [tag=tag-name,] key key-value[:key-type] in container do
code}
where:
tag-nameis a unique tag name for this loop. The tag name is optional. Specify a tag name if you want to use the continue or break expressions with tag names in code. Specify a valid Curl language identifier. For more information, see continue and break.
key-valueis the name of the variable that will contain the key for the element on each iteration. Specify a unique identifier.
key-typeis the data type of the variable that will contain the key. Specifying the data type is optional. If you do not specify it, the data type is inferred.
containeris the container object. Valid container objects include strings, arrays, sets, and hash tables.
codeconsists of one or more Curl language expressions.
When the runtime encounters such a for expression, it executes code for each element in container. On each iteration through code, it assigns the key for the element in question to key-value. For example:

Example: Using the {for key ... in ... do ...} Container Loop
{value
    || Define a vertical box variable called message to store
    || and display a string.
    let message:VBox={VBox}

    || Define a as an array of integers with three values (10,
    || 20, and 30).
    let a:{Array-of int}={{Array-of int} 10, 20, 30}

    || For each key k in the array, place k in
    || message.
    {for key k:int in a do
        {message.add k}
    }

    || Display the contents of message.
    message
}
In the example above, the resulting array contains the values of the keys. Compare the code and results of that example to the example in the previous section ( for ... in ... do ...).
{for ... key ... in ... do ...}
In this form of the for container loop, the runtime assigns the value of the element in question to a variable and the key for the element in question to another variable. This form has the following syntax:
Syntax:{for [tag=tag-name,] element-value[:element-type] key key-value[:key-type] in container do
code }
where:
tag-nameis a unique tag name for this loop. The tag name is optional. Specify a tag name if you want to use the continue or break expressions with tag names in code. Specify a valid Curl identifier. For more information, see continue and break.
element-valueis the name of the variable that will contain the value of the element on each iteration. Specify a unique identifier.
element-typeis the data type of the variable that will contain the element. Specifying the data type is optional. If you do not specify it, the data type is inferred.
key-valueis the name of the variable that will contain the key for the element on each iteration. Specify a unique identifier.
key-typeis the data type of the variable that will contain the key. Specifying the data type is optional. If you do not specify it, the data type is inferred.
containeris the container object. Valid container objects include strings, arrays, sets, and hash tables.
codeconsists of one or more Curl language expressions.
When the runtime encounters such a for expression, it executes code for each element in container. On each iteration through code, it assigns the value of the element in question to element-value and the key for the element in question to key-value. For example:

Example: Using the {for ... key ... in ... do ...} Container Loop
{value
    || Define a vertical box variable called message to store
    || and display a string.
    let message:VBox={VBox}

    || Define a as an array of integers with three values (10,
    || 20, and 30).
    let a:{Array-of int}={{Array-of int} 10, 20, 30}

    || For each iteration, place the value v and the key
    || k in message.
    {for v:int key k:int in a do
        {message.add {text {value k} ... {value v}}}
    }

    || Display the contents of message.
    message
}