Skip to content

Commit 0ad20e7

Browse files
authored
[spec/statement.dd] Improve 'Foreach over Structs & Classes with Ranges' (#3204)
* [spec/statement.dd] Improve 'Foreach over Structs & Classes with Ranges' Link to std.range. Add example using linked list. Add 'Multiple Element Values' subheading. Fix tuple -> sequence typo. Fix tuple front example to not infinite loop & make runnable. Show single variable is still legal. * Define `Tuple` struct instead of importing `std.typecons`
1 parent f88fca2 commit 0ad20e7

File tree

1 file changed

+61
-14
lines changed

1 file changed

+61
-14
lines changed

spec/statement.dd

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -760,8 +760,8 @@ $(CONSOLE
760760
$(H3 $(LEGACY_LNAME2 foreach_with_ranges, foreach-with-ranges, Foreach over Structs and Classes with Ranges))
761761

762762
$(P If the aggregate expression is a struct or class object, but the
763-
$(D opApply) for $(D foreach), or $(D opApplyReverse) $(D foreach_reverse) do not exist,
764-
then iteration over struct and class objects can be done with range primitives.
763+
$(D opApply) for $(D foreach), or $(D opApplyReverse) for $(D foreach_reverse) do not exist,
764+
then iteration can be done with $(LINK2 $(ROOT_DIR)phobos/std_range.html, range) primitives.
765765
For $(D foreach), this means the following properties and methods must
766766
be defined:
767767
)
@@ -826,42 +826,89 @@ $(H3 $(LEGACY_LNAME2 foreach_with_ranges, foreach-with-ranges, Foreach over Stru
826826
}
827827
---
828828

829+
$(P Example with a linked list:)
830+
831+
$(SPEC_RUNNABLE_EXAMPLE_RUN
832+
---
833+
struct Node
834+
{
835+
int i;
836+
Node* next;
837+
}
838+
839+
// range
840+
struct List
841+
{
842+
Node* node;
843+
844+
bool empty() { return node == null; }
845+
846+
ref int front() { return node.i; }
847+
848+
void popFront() { node = node.next; }
849+
}
850+
851+
void main()
852+
{
853+
import std.stdio;
854+
auto l = new Node(1, new Node(2, null));
855+
auto r = List(l);
856+
857+
foreach (e; r)
858+
{
859+
writeln(e);
860+
}
861+
}
862+
---
863+
)
864+
865+
$(H4 $(LNAME2 front-seq, Multiple Element Values))
866+
829867
$(P Multiple loop variables are allowed if the `front` property returns a type that
830868
expands to an $(DDSUBLINK spec/template, variadic-templates, expression sequence)
831869
whose size matches the number of variables. Each variable is assigned
832-
to the corresponding value in the tuple.
870+
to the corresponding value in the sequence.
833871
)
834872

873+
$(SPEC_RUNNABLE_EXAMPLE_RUN
835874
---
836-
// Common tuple implementation that can decay into its members
837-
import std.typecons : Tuple;
875+
struct Tuple(Types...) // takes a TypeSeq
876+
{
877+
Types items; // ValueSeq
878+
alias items this; // decay to a value sequence
879+
}
838880

839-
// Range whose elements are tuples
881+
// Infinite range whose element is a fixed tuple
840882
struct TupleRange
841883
{
842-
Tuple!(char, bool, int) front()
843-
{
844-
return typeof(return)('a', true, 2);
845-
}
884+
enum front = Tuple!(char, bool, int)('a', true, 2);
846885

847-
bool empty() { return false; }
886+
enum bool empty = false;
848887

849888
void popFront() {}
850889
}
851890

852891
void main()
853892
{
893+
// Tuple destructuring
854894
foreach (a, b, c; TupleRange())
855895
{
856896
assert(a == 'a');
857897
assert(b == true);
858898
assert(c == 2);
899+
break;
900+
}
901+
// Tuple variable
902+
foreach (tup; TupleRange())
903+
{
904+
assert(tup[0] == 'a');
905+
assert(tup == TupleRange.front);
906+
break;
859907
}
860-
861-
// Expected 3 arguments, not 1
862-
// foreach (a; TupleRange()) { ... }
863908
}
864909
---
910+
)
911+
$(P See also: $(REF Tuple, std,typecons).)
865912

866913
$(H3 $(LNAME2 foreach_over_delegates, Foreach over Delegates))
867914

0 commit comments

Comments
 (0)