Skip to content

Commit 41f49bd

Browse files
committed
[spec/statement.dd] Improve foreach docs
Explain the variables declared in ForeachTypeList more. Move paragraph about inferring the type of the ForeachType declaration from the `ref` subheading to main foreach section. Also move note about `auto` being redundant from array subheading, along with the example. Modify the example as no need to show `auto` causing an error. Mark resizing/reassigning a container during foreach as undefined behaviour.
1 parent b579ac4 commit 41f49bd

File tree

1 file changed

+51
-43
lines changed

1 file changed

+51
-43
lines changed

spec/statement.dd

Lines changed: 51 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ for (int i = 0; i < 10; i++)
445445

446446
$(H2 $(LEGACY_LNAME2 ForeachStatement, foreach-statement, Foreach Statement))
447447

448-
$(P A `foreach` statement loops over the contents of an aggregate.)
448+
$(P A `foreach` statement iterates a series of values.)
449449

450450
$(GRAMMAR
451451
$(GNAME AggregateForeach):
@@ -483,26 +483,48 @@ $(GNAME ForeachAggregate):
483483

484484
$(P
485485
$(I ForeachAggregate) is evaluated. It must evaluate to an expression
486-
of type static array, dynamic array, associative array,
486+
which is a static array, dynamic array, associative array,
487487
struct, class, delegate, or sequence.
488488
The *NoScopeNonEmptyStatement* is executed, once for each element of the
489489
aggregate.
490-
At the start of each iteration, the variables declared by
491-
the $(I ForeachTypeList)
492-
are set to be a copy of the elements of the aggregate.
493-
If the $(I ForeachTypeAttribute) is $(D ref), it is a reference to the
494-
contents of that aggregate.
495-
If the $(I ForeachTypeAttribute) is $(D scope), the $(I ForeachType) declaration
496-
will have $(D scope) semantics.
497490
)
498491
$(P
499-
The aggregate must be loop invariant, meaning that
500-
elements to the aggregate cannot be added or removed from it
492+
The number of variables declared in $(I ForeachTypeList)
493+
depends on the kind of aggregate. The declared variables are
494+
set at the start of each iteration.
495+
)
496+
$(UL
497+
$(LI By default a single declared variable is a copy of the current element.)
498+
$(LI If the $(I ForeachTypeAttribute) is $(D ref), that variable will
499+
be a reference to the current element of the aggregate.)
500+
$(LI If the $(I ForeachTypeAttribute) is $(D scope), the variable
501+
will have $(DDSUBLINK spec/function, scope-parameters, `scope`) semantics.)
502+
)
503+
$(P
504+
If not specified, the type of a $(I ForeachType) variable
505+
can be inferred from the type of the $(I ForeachAggregate).
506+
Note that `auto` is not a valid $(I ForeachTypeAttribute).
507+
The two `foreach` statements below are equivalent:
508+
)
509+
$(SPEC_RUNNABLE_EXAMPLE_RUN
510+
--------------
511+
int[] arr = [1, 2, 3];
512+
513+
foreach (int n; arr)
514+
writeln(n);
515+
516+
foreach (n; arr) // ok, n is an int
517+
writeln(n);
518+
--------------
519+
)
520+
$(P
521+
The aggregate must be *loop invariant*, meaning that
522+
elements cannot be added or removed from the aggregate
501523
in the *NoScopeNonEmptyStatement*.
502524
)
503525

504526
$(P A $(GLINK BreakStatement) in the body of the foreach will exit the
505-
foreach, a $(GLINK ContinueStatement) will immediately start the
527+
loop. A $(GLINK ContinueStatement) will immediately start the
506528
next iteration.
507529
)
508530

@@ -541,21 +563,6 @@ foreach (size_t i, char c; a)
541563
order.
542564
)
543565

544-
$(P $(B Note:) The $(I ForeachTypeAttribute) is implicit, and when a
545-
type is not specified, it is inferred. In that case, $(D auto) is
546-
implied, and it is not necessary (and actually forbidden) to use it.
547-
)
548-
549-
--------------
550-
int[] arr;
551-
...
552-
foreach (n; arr) // ok, n is an int
553-
writeln(n);
554-
555-
foreach (auto n; arr) // error, auto is redundant
556-
writeln(n);
557-
--------------
558-
559566
$(H3 $(LNAME2 foreach_over_arrays_of_characters, Foreach over Arrays of Characters))
560567

561568
$(P If the aggregate expression is a static or dynamic array of
@@ -960,7 +967,8 @@ main()
960967

961968
$(H3 $(LNAME2 foreach_ref_parameters, Foreach Ref Parameters))
962969

963-
$(P $(D ref) can be used to update the original elements:
970+
$(P $(D ref) can be used to update the original elements for some
971+
kinds of container. Arrays support this:
964972
)
965973

966974
$(SPEC_RUNNABLE_EXAMPLE_RUN
@@ -984,30 +992,28 @@ $(CONSOLE
984992
8
985993
9
986994
)
987-
$(P $(D ref) can not be applied to the index values.)
988-
989-
$(P If not specified, the $(I Type)s in the $(I ForeachType) can be
990-
inferred from
991-
the type of the $(I ForeachAggregate).
992-
)
995+
$(P $(D ref) cannot be applied to an array index variable.)
993996

994997
$(H3 $(LNAME2 foreach_restrictions, Foreach Restrictions))
995998

996-
$(P The aggregate itself must not be resized, reallocated, free'd,
999+
$(UNDEFINED_BEHAVIOR The aggregate itself must not be resized, reallocated, free'd,
9971000
reassigned or destructed
9981001
while the foreach is iterating over the elements.
9991002
)
10001003

10011004
--------------
1002-
int[] a;
1003-
int[] b;
1004-
foreach (int i; a)
1005+
int[] a, b;
1006+
...
1007+
foreach (int v; a)
10051008
{
1006-
a = null; // error
1009+
a ~= 4; // error
10071010
a.length += 10; // error
1011+
1012+
a = null; // error
10081013
a = b; // error
10091014
}
1010-
a = null; // ok
1015+
a ~= 4; // OK
1016+
a = null; // OK
10111017
--------------
10121018

10131019
$(H3 $(LEGACY_LNAME2 ForeachRangeStatement, foreach-range-statement, Foreach Range Statement))
@@ -1030,11 +1036,13 @@ $(GNAME ForeachRangeStatement):
10301036

10311037
$(P
10321038
$(I ForeachType) declares a variable with either an explicit type,
1033-
or a type inferred from $(I LwrExpression) and $(I UprExpression).
1039+
or a common type inferred from $(I LwrExpression) and $(I UprExpression).
10341040
The $(I ScopeStatement) is then executed $(I n) times, where $(I n)
1035-
is the result of $(I UprExpression) - $(I LwrExpression).
1041+
is the result of $(I UprExpression) `-` $(I LwrExpression).
10361042
If $(I UprExpression) is less than or equal to $(I LwrExpression),
1037-
the $(I ScopeStatement) is executed zero times.
1043+
the $(I ScopeStatement) is not executed.)
1044+
1045+
$(P
10381046
If $(I Foreach) is $(D foreach), then the variable is set to
10391047
$(I LwrExpression), then incremented at the end of each iteration.
10401048
If $(I Foreach) is $(D foreach_reverse), then the variable is set to

0 commit comments

Comments
 (0)