More powerful foreach statements

kris foo at bar.com
Thu Jul 20 11:03:21 PDT 2006


Ben Phillips wrote:
> 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.
> 
> 


Both can be done right now:

1)  foreach (int i, Foo f; ManyFooInstance)
              if (i is 0)
                  ....

Or somthing like that.


2) foreach (int element; collection.reverse)
	    ...

where #2 returns a type which supports foreach. Typically, this would be 
some kind of Iterator construct. IIRC, someone already has a framework 
for such things? Was it Oskar?



More information about the Digitalmars-d mailing list