More powerful foreach statements

Ben Phillips Ben_member at pathlink.com
Thu Jul 20 10:48:34 PDT 2006


While D's foreach is a much appreciated improvement over C++'s template version,
I feel there are still some ways in which it can be improved. I listed two ideas
below, though if you're in a hurry you can just skip to the second one because
thats the most interesting one (imo).

First proposal: an index tracker
Recently there was a suggestion to allow "first" and "last" blocks in a foreach
statement. This would allow things such as special initialization to get done
during the first iteration through the foreach and possible clean-up work to get
done during the last iteration. The current solution is to either go with a
conventional "for" loop or to create a counter of some sort that counts what
iteration the foreach statement is in (Though I'm not sure how one would detect
the last iteration with a counter).

It would convenient if a foreach statement automatically kept track of the
iteration number.
Example:
foreach(Foo f; ManyFoos mf)
{
if (_iteration == 0)
// special stuff on first iteration here
.. 
}

The _iteration variable should follow normal scoping rules so nested foreach
statements can still access their own iteration counters.

Second proposal: opApply variants
This proposal is more radical than the last. One of the largest problems I have
with foreach statements is that [afaik] iteration can only be done in one
direction. For example, it is easy to use a foreach statement to iterate through
an array starting at index zero but impossible to do it in reverse. The only way
I know to work around this is the following:
class Collection
{
private bool reverse = false;
public Collection reverse()
{
// either sets reverse = true (therefore requiring it to get set back) or
// duplicates this whole collection and sets the reverse flag in that one
// (very expensive)
}
}

I believe a possible solution to this would be to allow one to write different
variants of opApply.
Example:
class Collection(T)
{
// normal opApply
int opApply(int delegate(inout T) dg) { ... }
// reverse order
int opApply|reverse|(int delegate(inout T) dg) { ... }
// some weird iteration pattern
int opApply|weird|(int delegate(inout T) dg) { ... }
}

Usage:
Collection!(int) collection = new Collection!(int)();
..
// to do a reverse order iteration
foreach|reverse|(int element; collection) { ... }
// a weird order one
foreach|weird|(int element, collection) { ... }

The idea is that within the function "opApply" there can be different variants
that can created through use of another string placed inbetween pipe characters
("|"). This string can be whatever the class author feels is appropriate. This
allows for easy implementation of different types of iteration that can be used
with a foreach statement, while still allowing the compiler to recognize the
"opApply" function.

Technically the idea above could also be applied to other functions, however its
usefulness degrades since most functions can just be renamed for different
variants while opApply cannot.





More information about the Digitalmars-d mailing list