version 6.0
The formal syntax of the For...End for control flow structure is:
For (Counter_Variable; Start_Expression; End_Expression {; Increment_Expression}) statement(s) End for
The For...End for loop is a loop controlled by a counter variable:
The counter variable Counter_Variable is a numeric variable (Real, Integer, or Long Integer) that the For...End for loop initializes to the value specified by Start_Expression.
Each time the loop is executed, the counter variable is incremented by the value specified in the optional value Increment_Expression. If you do not specify Increment_Expression, the counter variable is incremented by one (1), which is the default.
When the counter variable passes the End_Expression value, the loop stops.
Important: The numeric expressions Start_Expression, End_Expression and Increment_Expression are evaluated once at the beginning of the loop. If these expressions are variables, changing one of these variables within the loop will not affect the loop.
Tip: However, for special purposes, you can change the value of the counter variable Counter_Variable within the loop; this will affect the loop.
Usually Start_Expression is less than End_Expression.
If Start_Expression and End_Expression are equal, the loop will execute only once.
If Start_Expression is greater than End_Expression, the loop will not execute at all unless you specify a negative Increment_Expression. See the examples.
Basic Examples
1. The following example executes 100 iterations:
For (vCounter;1;100) ` Do something End for
2. The following example goes through all elements of the array anArray:
For ($vlElem;1;Size of array(anArray)) ` Do something with the element anArray{$vlElem}:=... End for
3. The following example goes through all the characters of the text vtSomeText:
For ($vlChar;1;Length(vtSomeText)) ` Do something with the character if it is a TAB If (Ascii(vtSomeText[[$vlChar]])=Char(Tab)) ` ... End if End for
4. The following example goes through the selected records for the table [aTable]:
FIRST RECORD([aTable]) For ($vlRecord;1;Records in selection([aTable])) ` Do something with the record SEND RECORD([aTable]) ` ... ` Go to the next record NEXT RECORD([aTable]) End for
Most of the For...End for loops you will write in your databases will look like the ones listed in these examples.
Decrementing variable counter
In some cases, you may want to have a loop whose counter variable is decreasing rather than increasing. To do so, you must specify Start_Expression greater than End_Expression and a negative Increment_Expression. The following examples do the same thing as the previous examples, but in reverse order:
5. The following example executes 100 iterations:
For (vCounter;100;1;-1) ` Do something End for
6. The following example goes through all elements of the array anArray:
For ($vlElem;Size of array(anArray);1;-1) ` Do something with the element anArray{$vlElem}:=... End for
7. The following example goes through all the characters of the text vtSomeText:
For ($vlChar;Length(vtSomeText);1;-1) ` Do something with the character if it is a TAB If (Ascii(vtSomeText[[$vlChar]])=Char(Tab)) ` ... End if End for
8. The following example goes through the selected records for the table [aTable]:
LAST RECORD([aTable]) For ($vlRecord;Records in selection([aTable]);1;-1) ` Do something with the record SEND RECORD([aTable]) ` ... ` Go to the previous record PREVIOUS RECORD([aTable]) End for
Incrementing the counter variable by more than one
If you need to, you can use an Increment_Expression (positive or negative) whose absolute value is greater than one.
9. The following loop addresses only the even elements of the array anArray:
For ($vlElem;2;((Size of array(anArray)+1)\2)*2;2) ` Do something with the element #2,#4...#2n anArray{$vlElem}:=... End for
Note that the ending expression ((Size of array(anArray)+1)\2)*2 takes care of even and odd array sizes.
Getting out of a loop by changing the counter variable
In some cases, you may want to execute a loop for a specific number of iterations, but then get out of the loop when another condition becomes TRUE. To do so, you can test this condition within the loop and if it becomes TRUE, explicitly set the counter variable to a value that exceeds the end expression.
10. In the following example, a selection of the records is browsed until this is actually done or until the interprocess variable <>vbWeStop, intially set to FALSE, becomes TRUE. This variable is handled by an ON EVENT CALL project method that allows you to interrupt the operation:
<>vbWeStop:=False ON EVENT CALL ("HANDLE STOP") ` HANDLE STOP sets <>vbWeStop to True if Ctrl-period (Windows) or Cmd-Period (Macintosh) is pressed $vlNbRecords:=Records in selection([aTable]) FIRST RECORD([aTable]) For ($vlRecord;1;$vlNbRecords) ` Do something with the record SEND RECORD([aTable]) ` ... ` Go to the next record If (<>vbWeStop) $vlRecord:=$vlNbRecords+1 ` Force the counter variable to get out of the loop Else NEXT RECORD([aTable]) End if End for ON EVENT CALL("") If (<>vbWeStop) ALERT("The operation has been interrupted.") Else ALERT("The operation has been successfully completed.") End if
Comparing looping structures
Let's go back to the first For...End for example:
The following example executes 100 iterations:
For (vCounter;1;100) ` Do something End for
It is interesting to see how the While...End while loop and Repeat...Until loop would perform the same action.
Here is the equivalent While...End while loop:
$i := 1 ` Initialize the counter While ($i<=100) ` Loop 100 times ` Do something $i := $i + 1 ` Need to increment the counter End while
Here is the equivalent Repeat...Until loop:
$i := 1 ` Initialize the counter Repeat ` Do something $i := $i + 1 ` Need to increment the counter Until ($i=100) ` Loop 100 times
Tip: The For...End for loop is usually faster than the While...End while and Repeat...Until loops, because 4th Dimension tests the condition internally for each cycle of the loop and increments the counter. Therefore, use the For...End for loop whenever possible.
Optimizing the execution of the For...End for loops
You can use Real, Integer, and Long Integer variables as well as interprocess, process, and local variable counters. For lengthy repetitive loops, especially in compiled mode, use local Long Integer variables.
11. Here is an example:
C_LONGINT($vlCounter) ` use local Long Integer variables
For ($vlCounter;1;10000) ` Do something End for
Nested For...End for looping structures
You can nest as many control structures as you (reasonably) need. This includes nesting For...End for loops. To avoid mistakes, make sure to use different counter variables for each looping structure.
Here are two examples:
12. The following example goes through all the elements of a two-dimensional array:
For ($vlElem;1;Size of array(anArray)) ` ... ` Do something with the row ` ... For ($vlSubElem;1;Size of array(anArray{$vlElem})) ` Do something with the element anArray{$vlElem}{$vlSubElem}:=... End for End for
13. The following example builds an array of pointers to all the date fields present in the database:
ARRAY POINTER($apDateFields;0) $vlElem:=0 For ($vlTable;1;Count table) For($vlField;1;Count fields($vlTable)) $vpField:=Field($vlTable;$vlField) If (Type($vpField->)=Is Date) $vlElem:=$vlElem+1 INSERT ELEMENT($apDateFields;$vlElem) $apDateFields{$vlElem}:=$vpField End if End for End for
See Also
Case of...Else...End case, Control Flow, If...Else...End if, Repeat...Until, While...End while.