-
-
Notifications
You must be signed in to change notification settings - Fork 701
Support foreach when range front converts to a sequence of functions #22828
Description
https://dlang.org/spec/statement.html#front-seq:
Multiple loop variables are allowed if the front property returns a type that expands to a value sequence whose length matches the number of variables
Now that #21296 is fixed, it would be useful to extend the above feature to allow destructuring a sequence of functions (or a sequence of values and functions). Particularly when the function returns by ref, so the corresponding foreach parameter can be ref. Example:
// range for iterating a slice
struct R
{
char[] a;
int i = 0;
@property bool empty() => i == a.length;
@property auto front()
{
struct E
{
R* p;
private alias Seq(A...) = A;
alias expand = Seq!(index, value);
alias this = expand;
@property int index() => p.i;
@property ref char value() => p.a[p.i];
}
return E(&this);
}
void popFront() { i++; }
}
char[2] arr = "hi";
void main()
{
R r = R(arr);
foreach (e; r)
{
// alias this now works
writeln(e[0], ": ", e[1]);
e[1] = cast(char)(e[0] + 'a');
}
assert(arr == "ab");
foreach (i, c; r) {} // Error: cannot infer argument types, expected 1 argument, not 2
foreach (i, ref c; r) {} // Error, should work too
}A real world use for this would be making object.byKeyValue(aa).front have a type with an alias this to a sequence of its key and value accessor methods. The point of that is so that an element of byKeyValue could be used with foreach destructuring (and also tuple unpacking syntax when @tgehr's implementation is merged):
auto dict = ["k1": 1, "k2": 2];
foreach (k, v; dict.byKeyValue) { ... }
foreach (k, ref v; dict.byKeyValue) { ... } // allows modifying each `v`