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_Variablewithin 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.
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(Character code(vtSomeText[[$vlChar]])=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.
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(Character code(vtSomeText[[$vlChar]])=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
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
$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 4D tests the condition internally for each cycle of the loop and increments the counter. Therefore, use the For...End for loop whenever possible.
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
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;Get last table number) If(Is table number valid($vlTable)) For($vlField;1;Get last field number($vlTable)) If(Is field number valid($vlTable;$vlField)) $vpField:=Field($vlTable;$vlField) If(Type($vpField->)=Is date) $vlElem:=$vlElem+1 INSERT IN ARRAY($apDateFields;$vlElem) $apDateFields{$vlElem}:=$vpField End if End if End for End if End for