Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[spec/statement.dd] Improve 'Foreach over Structs & Classes with Ranges' #3204

Merged
merged 2 commits into from Feb 1, 2022
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
66 changes: 56 additions & 10 deletions spec/statement.dd
Expand Up @@ -761,8 +761,8 @@ $(CONSOLE
$(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) $(D foreach_reverse) do not exist,
then iteration over struct and class objects can be done with range primitives.
$(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:
)
Expand Down Expand Up @@ -827,42 +827,88 @@ $(H3 $(LEGACY_LNAME2 foreach_with_ranges, foreach-with-ranges, Foreach over Stru
}
---

$(P Example with a linked list:)

$(SPEC_RUNNABLE_EXAMPLE_RUN
---
struct Node
{
int i;
Node* next;
}

// range
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);

foreach (e; r)
{
writeln(e);
}
}
---
)

$(H4 $(LNAME2 front-seq, Multiple Element Values))

$(P Multiple loop variables are allowed if the `front` property returns a type that
expands to an $(DDSUBLINK spec/template, variadic-templates, expression sequence)
whose size matches the number of variables. Each variable is assigned
to the corresponding value in the tuple.
to the corresponding value in the sequence.
)

$(SPEC_RUNNABLE_EXAMPLE_RUN
---
// Common tuple implementation that can decay into its members
import std.typecons : Tuple;
// Common tuple implementation that can decay into a sequence of its members
import std.typecons : Tuple, tuple;

// Range whose elements are tuples
// Infinite range whose elements are tuples
struct TupleRange
{
Tuple!(char, bool, int) front()
{
return typeof(return)('a', true, 2);
}

bool empty() { return false; }
enum bool empty = false;

void popFront() {}
}

void main()
{
// Tuple destructuring
foreach (a, b, c; TupleRange())
{
assert(a == 'a');
assert(b == true);
assert(c == 2);
break;
}
// Tuple variable
foreach (a; TupleRange())
{
assert(a == tuple('a', true, 2));
break;
}

// Expected 3 arguments, not 1
// foreach (a; TupleRange()) { ... }
}
---
)
$(P See also: $(REF Tuple, std,typecons).)

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

Expand Down