More powerful foreach statements

Oskar Linde oskar.lindeREM at OVEgmail.com
Fri Jul 21 04:33:05 PDT 2006


pragma wrote:
> In article <e9ogh7$b1b$1 at digitaldaemon.com>, kris says...
>> 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,
> [snipped foreach proposal]
> Being able to get at the current iteration would be nice, but its certainly
> sugar.  The only way I can see this single case being covered, is with a third
> foreach arg, like so:
> 
> foreach(uint i,key,value; myAA){
> }
> 
> .. as this makes a rather nice, logical extension to things IMO.  But I'm not
> holding my breath for its inclusion into D. ;)
> 
> A variation would be to use a specialized iterator:
> 
> uint i;
> foreach(key,value; myAA.forward(&i){
> //i is incremented for each call of opApply()
> }

or why not:
uint i = -1;
foreach(key,value; myAA) {
	i++;
	...
}

:)

>> IIRC, someone already has a framework 
>> for such things? Was it Oskar?
> 
> I remember seeing a heavily templated Array library posted here, that Andrew
> made a while back, could that be it?  It was drafted well before implicit
> templates were available, so maybe its worth reviewing again.

I also posted a templated array library suggestion earlier. It was 
drafted just after the inclusion of implicit function template 
instantiation and was designed to work with the current limited ifti 
support. The code would be a lot nicer if we got a more complete ifti 
support implemented though.

The implementation and (ugly) ddoc:

http://www.csc.kth.se/~ol/array.d
http://www.csc.kth.se/~ol/array.html

It doesn't currently contain any iterator functions. I've been toying 
with that a little though and have things like these working:

// pensionCosts is 4 % of the net salary of employees older than 28 yrs
// assume Employee[] employees;
double pensionCosts = 0;
foreach(e; employees.select((Employee e) { return e.age >= 28; }))
	pensionCosts += employee.salary * 0.04;

Reverse iterators: (I haven't currently implemented reverse utf 
conversions, like foreach(dchar c; "abcd"c.reverseIterator()). It is a 
lot of work and I'm not sure they are worth it.)

foreach(x; "abcd".reverseIterator())
	writefln("x = %s",x);

Python style ranges:

foreach(x; range(5))
	... x is 0,1,2,3,4
foreach(x; range(1, 6))
	... x is 1,2,3,4,5
foreach(x; range(1.5, 0, -0.25)) // bad idea to support doubles?
	... x is 1.5, 1.25, 1.0, 0.75, 0.5, 0.25

I've not found a good iterator design yet though. Only supporting 
foreach style iteration is a bit too limited.

I would also like array views to work as iterators and also support 
common array operations without having to generate temporary arrays.

Currently:

double pensionCosts = employees
          .filter((Employee e) { return e.age >= 28; })
          .map((Employee e) { return e.salary * 0.04; })
          .sum();

Will generate a temporary Employee[] array and a temporary double[] array.

Using array views one could get around the temporaries:

// give all employees over 55 a 3 % raise:

employees.select((Employee e) { return e.age >= 55; })
          .update((Employee e) { e.salary *= 1.03; });

//(No temporaries created.)

/Oskar



More information about the Digitalmars-d mailing list