Xbasic GuideLoop Statements

A statement that executes the same block of code multiple times is called a loop statement. Loops are used to perform some action for multiple entries in an array or while waiting for a response to an asynchronous action, such as Queues or callbacks.

Loops are created in Xbasic using FOR and WHILE statements.

FOR Loops

An Xbasic FOR loops is used to repeat a block of code a specified number of times. The FOR loop statement includes a numeric counter, a start value, and an end value. Each time the FOR loop executes, the counter is increased by 1.

DIM countingMsg AS C = ""
FOR counter = 1 TO 10
    'Count to 10 in the trace log
    countingMsg = countingMsg + counter + crlf()
showvar(countingMsg,"Counting from 1 to 10")

You can optionally specify a STEP value if you wish to increment the counter by a value that is not 1.

FOR counter = start TO end STEP increment
    'Xbasic code to execute

The STEP value can be any numeric number. For example, you can count backward from 10 to 1 by specifying a STEP of -1:

countingMsg = ""
FOR counter = 10 TO 1 STEP -1
    'Count from 10 to 1
    countingMsg = countingMsg + counter + crlf()
showvar(countingMsg,"Counting Backwards")

countingMsg = ""
FOR counter = 0 TO 10 STEP 2
    'Count from 0 to 10 by 2
    countingMsg = countingMsg + counter + crlf()
showvar(countingMsg,"Counting by 2s")

You can optionally include the variable name for the counter in the NEXT statement for the FOR loop.

countingMsg = ""
DIM counter AS N
FOR x = 1 TO 10
    FOR y = 1 TO 10
        'Count to 100
        counter = 10 * (x - 1) + y
        countingMsg = countingMsg + counter + crlf()
    NEXT y
showvar(countingMsg,"Counting from 1 to 100")

It is not required to include the counter variable in the NEXT statement. However, for long scripts or scripts with multiple FOR loops, it is useful to include the counter to document which FOR loop matches the NEXT statement.

FOR EACH: Looping Over Lists, Collections, or Arrays

The FOR EACH loop is a type of FOR loop for iterating over a data set stored in a character list, collection, or array. Instead of using a counter to track progress through the loop, the FOR EACH loop iterates over entries in an object.

FOR EACH element IN object
    ' Xbasic code to execute

The value of the current entry in the object can be accessed using the value property of the element.

valueOfElement = element.value

For example, consider the following list of cities and counties:

DIM places AS C = <<%txt%
Mexico City,Mexico
Wellington,New Zealand
Vanuatu,Port Vila
Cape Town,South Africa

The following FOR EACH loop builds a list of countries from the places list:

DIM countries AS C
FOR EACH place IN places
    'Get the value of the current element
    currentPlace = place.value

    'Get the country name
    country = word(currentPlace,2,",")

    'Add the country name to the countries list
    'if the country is not in the list yet
    IF (country !$ countries) THEN
        countries = countries + country + crlf()
    END IF

When we run the script, the country list is displayed:


Skipping FOR Loop Iterations

It may not be necessary to execute a FOR loop until the loop's terminating condition evaluates to true (.T.). In some cases, you may only need to execute the code in the loop for some of the elements in the object. Iterations in a loop can be skipped using the CONTINUE keyword.

For example, using the places list created earlier, we could write the following script to create a list of countries that are not in North America:

'Create a list of places that are not in North America:
DIM nonNorthAmericaPlaces as C
DIM northAmerica as C = "USA,Canada,Mexico"
FOR EACH place IN places
    country = word(place.value,2,",")
    'Check to see if country is in Europe
    IF (country $ northAmerica)
        CONTINUE 'place is in North America, skip rest FOR loop
    END IF
    'Add the place to the nonNorthAmericaPlaces list
    nonNorthAmericaPlaces = nonNorthAmericaPlaces + place.value + crlf()
showvar(nonNorthAmericaPlaces,"Places not in North America")

If the country name is in the list of North American countries (northAmerica), the CONTINUE statement is executed, skipping the remainder of the current iteration of the FOR EACH loop and moving to the next entry in the places list.

Exiting FOR and FOR EACH Loops

You can exit a FOR loop or FOR EACH loop at any time using the EXIT FOR statement. EXIT FOR terminates the FOR loop and proceeds to the next line of code after the NEXT statement. For example, the script below searches the list of places for the city, Copenhagen. Once the city is found, there is no need to continue searching the rest of the list of places, so the FOR loop terminates with the EXIT FOR statement:

'Find the Country for "Copenhagen"
DIM country AS C
FOR EACH place IN places
    currentPlace = place.value
    city = word(currentPlace,1,",")
    IF (city = "Copenhagen")
        'Country found
        country = word(place.value,2,",")
        EXIT FOR 'Exit the FOR loop because we found the country
    END IF
showvar(country,"Copenhagen is located in...")


WHILE ... END WHILE is a control structure that repeats the statements it contains while the Logical Expression evaluates to true (.T.). Execution resumes at the line following the END WHILE statement when the Logical Expression is false (.F.) or when the EXIT WHILE statement executes.

countingMsg = ""
counter = 1
WHILE counter <= 100
    countingMsg = countingMsg + counter + crlf()
    'Increment counter by 1
    counter = counter + 1
showvar(countingMsg,"Counting from 1 to 100")

Exiting WHILE Loops

Similar to FOR and FOR EACH loops, you can terminate WHILE loops early using the EXIT WHILE statement. For example, the code below computes the date of the next Tuesday for the current month. If no Tuesday is found before the end of the month (the value of the current month does not match the month of the nextDay variable), the WHILE loop terminates, and a message is shown stating that there are no Tuesdays left in the month.

noMoreTuesdays = .F.
today = now()
nextDay = today + 1
currentMonth = month(today)

WHILE 3 != dow(nextDay) ' 3 = Tuesday
    IF (currentMonth <> month(nextDay)) THEN
       ' The month changed; there are no more Tuesdays
       ' Exit the WHILE loop
        noMoreTuesdays = .T.
        EXIT WHILE
    END IF
    nextDay = nextDay + 1

IF (noMoreTuesdays) THEN
    showvar("There are no more Tuesdays this month.")
    showvar("The next Tuesday is on " + nextDay)