-
Notifications
You must be signed in to change notification settings - Fork 20
for statement
The for
statement is generally used to loop over a range of values or the contents of a data structure, executing a block of code for each loop iteration. It is, in many ways, a construct of convenience, intended to eliminate a few lines of code that would be necessary to accomplish the same result with a while
or do
statement. As such, its purpose is to assist both in the writeability and readability for a number of common patterns in looping code, while helping to reduce errors.
There are two forms of the ForStatement, based on two different forms of the ForCondition. The first is the traditional C-style for
condition that has a separate initialization, test, and modification section. The second is the "for-each" style that specifies a range of values or a value of a container type whose values are to be iterated. These two forms will be explored separately, below.
ForStatement: for ( ForCondition ) StatementBlock ForCondition: VariableInitializationListopt ; ConditionListopt ; VariableModificationListopt OptionalDeclaration : Expression ( OptionalDeclarationList , OptionalDeclaration ) : Expression VariableInitializationList: VariableInitializer VariableInitializationList , VariableInitializer VariableInitializer: OptionalDeclaration = Expression ( OptionalDeclarationList , OptionalDeclaration ) = Expression VariableModificationList: VariableModification VariableModificationList , VariableModification VariableModification: Assignment Expression
From IfStatement:
ConditionList: Condition ConditionList , Condition Condition: Expression OptionalDeclaration ConditionalAssignmentOp Expression ( OptionalDeclarationList , OptionalDeclaration ) ConditionalAssignmentOp Expression ConditionalAssignmentOp: := ?=
And from VariableStatement:
OptionalDeclarationList: OptionalDeclaration OptionalDeclarationList , OptionalDeclaration OptionalDeclaration: Assignable VariableTypeExpression Name VariableTypeExpression: val var TypeExpression Assignable: Name TernaryExpression . Name TernaryExpression ArrayIndexes
The C-style for
statement uses a three-part ForCondition, any part of which can be left blank:
- An initialization portion, which is performed when the statement is entered;
- A test portion, which is performed at the beginning of each iteration;
- A modification portion, which is performed at the end of each iteration.
The initialization portion is used to configure the initial state of the loop. Any number of declarations and assignments can be included in this portion; for example:
x=0, Int i=3, String s="hello", nums[0]=0, Boolean f=False
The test portion is a ConditionList that yields a Boolean
value, similar to that used in the IfStatement; for example:
x<100 && s=="hello"
Lastly, the modification portion allows a number of actions to be performed at the end of each loop iteration:
++x, foo(), i *= 2, f = !f
The above examples are atrocious in terms of readability; they are intended solely to illustrate the richness of the capabilities of the for
statement. For readability, the initialization portion should only be used to declare and initialize (i) loop control variables and (ii) variables local to the loop whose state is carried over from one iteration to the next. Similarly, the modification portion should be limited, as much as possible, to modifying only loop control variables.
In general terms, the C-style of for
statement can be re-written as a while statement; consider:
for (A; B; C)
{
D;
}
The above for
statement could be re-written as a while statement inside of a statement block:
{
A;
while (B)
{
D;
C;
}
}
Combined with the possibility of a continue
statement within the loop body, it quickly becomes obvious why the C-style for
statement exists; the alternative approaches are simply too ugly and unwieldy.
Execution of the for
statement begins with the execution of the VariableInitializationList, if any. Each comma-separated item in the initialization section is executed left-to-right and permitted to short-circuit; when a short-circuit occurs, execution continues with the next item. Then the test section, if specified, is evaluated: If it yields the Boolean
value False
, or it short-circuits, then the for
statement completes; otherwise, if it yields the Boolean
value True
, or if no test portion is specified, then the statement block body of the for
statement is executed. Then the execution proceeds to the VariableModificationList, if any; like the initialization section, each comma-separated item in the modification section is evaluated left-to-right and permitted to short-circuit, and a short-circuit causes execution to continue with the next item. Finally, the for
statement loops back to the test section.
Execution of a break
statement that applies to the for
statement causes the for
statement to complete.
Execution of a continue
statement that applies to the for
statement causes the for
statement to advance its execution to the VariableModificationList.
Like the while
statement, the for
statement labeled by a LabeledStatement provides two read-only label variables that expose the state of the loop:
Name | Type | Description |
---|---|---|
first |
Boolean |
True iff this is the first iteration of the loop |
count |
Int |
The count of completed iterations of the loop |
The VariableInitializationList of VariableInitializers is reachable if the for
statement is reachable. The first VariableInitializer is reachable if the VariableInitializationList is reachable. If a VariableInitializer short-circuits, then the VariableInitializer completes. Each subsequent VariableInitializer is reachable if the VariableInitializer preceding it completes. The VariableInitializationList completes if it is reachable and its last VariableInitializer completes; if there is no VariableInitializationList (i.e. if the list is empty), then the VariableInitializationList is considered to complete if it is reachable.
The test expression is reachable if the VariableInitializationList completes. If the test expression short-circuits, then the test expression completes as if it evaluated to the value False
. If the test expression is absent, then the test expression completes as if it were the constant value True
. The statement block body of the for
statement is reachable if the test expression completes and is not the constant value False
.
The VariableModificationList is reachable if the body completes or if a continue
statement that applies to the for
statement is reachable. The first VariableModification is reachable if the VariableModificationList is reachable. If a VariableModification short-circuits, then the VariableModification completes. Each subsequent VariableModification is reachable if the VariableModification preceding it completes. The VariableModificationList completes if it is reachable and its last VariableModification completes; if there is no VariableModificationList (i.e. if the list is empty), then the VariableModificationList is considered to complete if it is reachable.
The for
statement completes if the test expression completes and is not the constant True
, or if a break
statement that applies to the for
statement is reachable.
Definite assignment rules:
- The VAS before the VariableInitializationList is the VAS before the
for
statement. - The VAS before the first VariableInitializer is the VAS before the VariableInitializationList.
- The VAS before the each subsequent VariableInitializer is the VAS after the previous VariableInitializer.
- The VAS after the VariableInitializationList is the VAS after the last VariableInitializer. (In the case of an empty VariableInitializationList, the VAS after the VariableInitializationList is the VAS before the VariableInitializationList.)
- The VAS before the test expression is the VAS after the VariableInitializationList.
- If the test expression can short-circuit, then the VAS at each possible point of short-circuiting is joined with the VASF after the test expression.
- The VAS before the statement block is the VAST after the test expression.
- The VAS before the VariableModificationList is the VAS after the statement block.
- The VAS before the first VariableModification is the VAS before the VariableModificationList.
- The VAS before the each subsequent VariableModification is the VAS after the previous VariableModification.
- The VAS after the VariableModificationList is the VAS after the last VariableModification. (In the case of an empty VariableModificationList, the VAS after the VariableModificationList is the VAS before the VariableModificationList.)
- The VAS after the for statement is the VASF after the test expression joined with the VAS from each reachable break statement that applies to the for statement.
The for
statement provides a local variable scope for any declarations in the ForCondition; that scope exists to the end of the for
statement, which is to say that the statement block is nested within that scope. The statement block naturally provides a local variable scope, because it is a statement block.
The “for-each” style of the for
statement is used to loop over a range of values, or the contents of a container type, such as an Iterator
, Sequence
, List
, Array
, or Map
. For example:
for (String name : ["Tom", "Chris", "Caroline"])
{
console.println(name);
}
The supported types of the expression, in order of precedence, are:
-
Iterator
– Thefor
statement loops through the contents of theIterator
. -
Range
– Thefor
statement loops through the contents of theRange
by itsSequential
ElementType
(and not by using anIterator
). -
Sequence
– Thefor
statement loops through the contents of theSequence
using anInt
index (and not by using anIterator
). -
Map
– Thefor
statement creates anIterator
over thekeys
Set
(or theentries
Set
, if theEntry
or the value thereof is required) of theMap
, and then loops through the contents of theIterator
. -
Iterable
– Thefor
statement requests anIterator
from theIterable
object, and then loops through the contents of theIterator
.
Additionally, if the value from any of the above is a Tuple
, then the OptionalDeclaration permits assignment from the fields of the Tuple
. Consider the following example, in which a list contains tuples of first and last names:
String format(List<Tuple<String, String>> names)
{
StringBuffer result = "";
Append: for ((String first, String last) : names)
{
if (!Append.first)
{
result += ", ";
}
result += $"{first} {last}";
}
return result.toString();
}
The for
statement operating on an Iterator
or an Iterable
container and labeled by a LabeledStatement provides two read-only label variables that expose the state of the loop:
Name | Type | Description |
---|---|---|
first |
Boolean |
True iff this is the first iteration of the loop |
count |
Int |
The count of completed iterations of the loop |
The for
statement operating on a Range
or Sequence
and labeled by a LabeledStatement provides three read-only label variables that expose the state of the loop:
Name | Type | Description |
---|---|---|
first |
Boolean |
True iff this is the first iteration of the loop |
last |
Boolean |
True iff this is the last iteration of the loop |
count |
Int |
The count of completed iterations of the loop |
The for
statement operating on a Map<Key,Value>
and labeled by a LabeledStatement provides three read-only label variables that expose the state of the loop:
Name | Type | Description |
---|---|---|
first |
Boolean |
True iff this is the first iteration of the loop |
entry |
Entry |
The current Map.Entry being iterated |
count |
Int |
The count of completed iterations of the loop |
The ForCondition is reachable if the for
statement is reachable; the ForCondition completes if it is reachable and the expression completes or short-circuits. The statement block is reachable if the ForCondition expression completes (i.e. if the ForCondition can complete without the expression short-circuiting). The for
statement completes if the ForCondition completes.
Definite assignment rules:
- The VAS before the ForCondition is the VAS before the
for
statement. - The VAS before the statement block is the VAST after the ForCondition.
- If the ForCondition can short-circuit, then the VAS at each possible point of short-circuiting is joined with the VASF after the ForCondition.
- The VAS after the
for
statement is the VAS after the statement block joined with the VASF after the ForCondition.
The for
statement provides a local variable scope for any declarations in the ForCondition; that scope exists to the end of the for
statement, which is to say that the statement block is nested within that scope. The statement block naturally provides a local variable scope, because it is a statement block.