Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 40 additions & 17 deletions spec/statement.dd
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ $(H3 $(LNAME2 foreach_over_struct_and_classes, Foreach over Structs and Classes
These functions must each have the signature below:
)

$(GRAMMAR
$(INFORMATIVE_GRAMMAR
$(GNAME OpApplyDeclaration):
`int opApply` `(` `scope` `int delegate` `(` $(I OpApplyParameters) `)` `dg` `)` `;`

Expand Down Expand Up @@ -873,16 +873,18 @@ $(H4 $(LNAME2 template-op-apply, Template `opApply`))

$(H3 $(LEGACY_LNAME2 foreach_with_ranges, foreach-with-ranges, Foreach over Structs and Classes with Ranges))

$(P If the aggregate expression is a struct or class object, but the
$(D opApply) for $(D foreach), or $(D opApplyReverse) for $(D foreach_reverse) do not exist,
then iteration can be done with $(LINK2 $(ROOT_DIR)phobos/std_range.html, range) primitives.
For $(D foreach), this means the following properties and methods must
be defined:
$(P If the $(GLINK ForeachAggregate) is a struct or class object, but
$(RELATIVE_LINK2 foreach_over_struct_and_classes, `opApply`) does not exist,
then $(D foreach) iteration will use $(LINK2 $(ROOT_DIR)phobos/std_range.html, range)
primitives. These primitives produce a series of elements.
)
$(P The following properties and methods must
be defined for the $(I ForeachAggregate):
)

$(TABLE2 Foreach Range Properties,
$(THEAD Property, Purpose)
$(TROW $(ARGS $(D .empty)), $(ARGS returns true if no more elements))
$(TROW $(ARGS $(D .empty)), $(ARGS returns `true` if no more elements))
$(TROW $(ARGS $(D .front)), $(ARGS return the leftmost element of the range))
)

Expand All @@ -892,7 +894,8 @@ $(H3 $(LEGACY_LNAME2 foreach_with_ranges, foreach-with-ranges, Foreach over Stru
right by one))
)

$(P Meaning:)
$(P A temporary variable is used for iteration, which is initialized from the
*ForeachAggregate*. The statement:)

---
foreach (e; range) { ... }
Expand All @@ -908,13 +911,14 @@ $(H3 $(LEGACY_LNAME2 foreach_with_ranges, foreach-with-ranges, Foreach over Stru
}
---

$(P Similarly, for $(D foreach_reverse), the following properties and
methods must be defined:
$(P Similarly, for $(D foreach_reverse) when $(D opApplyReverse) is not defined,
range primitives will be used. The following properties and methods
must be defined for the $(I ForeachAggregate):
)

$(TABLE2 Foreach$(UNDERSCORE)reverse Range Properties,
$(THEAD Property, Purpose)
$(TROW $(ARGS $(D .empty)), $(ARGS returns true if no more elements))
$(TROW $(ARGS $(D .empty)), $(ARGS returns `true` if no more elements))
$(TROW $(ARGS $(D .back)), $(ARGS return the rightmost element of the range))
)

Expand All @@ -924,7 +928,7 @@ $(H3 $(LEGACY_LNAME2 foreach_with_ranges, foreach-with-ranges, Foreach over Stru
left by one))
)

$(P Meaning:)
$(P The statement:)

---
foreach_reverse (e; range) { ... }
Expand All @@ -940,6 +944,28 @@ $(H3 $(LEGACY_LNAME2 foreach_with_ranges, foreach-with-ranges, Foreach over Stru
}
---

$(P The $(GLINK ForeachType) variable may be declared with `ref` when `front`
(or `back` for `foreach_reverse`) is a
$(DDSUBLINK spec/function, ref-functions, Ref Function):)

$(SPEC_RUNNABLE_EXAMPLE_RUN
---
struct R
{
int[] a;
// range primitives:
bool empty() => a.length == 0;
ref front() => a[0];
void popFront() { a = a[1..$]; }
}

R r = R([1, 2, 3]);
foreach (ref e; r)
e *= 2;

assert(r.a == [2, 4, 6]);
---
)
$(P Example with a linked list:)

$(SPEC_RUNNABLE_EXAMPLE_RUN
Expand All @@ -954,19 +980,16 @@ struct Node
struct List
{
Node* node;

bool empty() { return node == null; }

ref int front() { return node.i; }

void popFront() { node = node.next; }
}

void main()
{
import std.stdio;
auto l = new Node(1, new Node(2, null));
auto r = List(l);
auto n = new Node(1, new Node(2, null));
auto r = List(n);

foreach (e; r)
{
Expand Down