Thread overview
Cool foreach loops
Feb 04, 2003
Bill Cox
Feb 05, 2003
Daniel Yokomiso
Feb 12, 2003
Bill Cox
Feb 14, 2003
Daniel Yokomiso
February 04, 2003
Hi.

I've been playing with foreach itterator syntax a bit.  This mechanism is complex, but very nice to use.  If it's not too complex to implement, I think it might be a nice enhancement to D.

Here's how it works.  In a container class, or any class that needs an itterator over children, define a loop function.  Here's an example for directed graphs:

class Node {
Edge firstIn, firstOut;
// This itterates through in edges
loop inEdges(Edge edge) {
for(edge = firstIn; edge != null; edge = edge.nextInEdge) {
doloop;
}
}
// This itterates through out edges
loop outEdges(Edge edge) {
for(edge = firstOut; edge != null; edge = edge.nextOutEdge) {
doloop;
}
}
// This itterates through all edges
loop edges(Edge edge) {
foreach(inEdges, edge) {
doloop;
}
foreach(outEdges, edge) {
doloop;
}
}
}

The foreach loops specify a loop function, and a loop variable.  The compiler can inline the loop functions to generate the expected code

Bill


February 05, 2003
In article <b1nrjp$1032$1@digitaldaemon.com>, Bill Cox says...
>
>Hi.
>
>I've been playing with foreach itterator syntax a bit.  This mechanism is complex, but very nice to use.  If it's not too complex to implement, I think it might be a nice enhancement to D.
>
>Here's how it works.  In a container class, or any class that needs an itterator over children, define a loop function.  Here's an example for directed graphs:
>
>class Node {
>Edge firstIn, firstOut;
>// This itterates through in edges
>loop inEdges(Edge edge) {
>for(edge = firstIn; edge != null; edge = edge.nextInEdge) {
>doloop;
>}
>}
>// This itterates through out edges
>loop outEdges(Edge edge) {
>for(edge = firstOut; edge != null; edge = edge.nextOutEdge) {
>doloop;
>}
>}
>// This itterates through all edges
>loop edges(Edge edge) {
>foreach(inEdges, edge) {
>doloop;
>}
>foreach(outEdges, edge) {
>doloop;
>}
>}
>}
>
>The foreach loops specify a loop function, and a loop variable.  The compiler can inline the loop functions to generate the expected code
>
>Bill
>
>

It looks very similar to Sather iterators, but less powerful, because it can iterate only over one iterator. There's some useful info at: http://www.icsi.berkeley.edu/~sather/Documentation/IteratorTutorial/ http://www.icsi.berkeley.edu/~sather/index.html http://www.cs.waikato.ac.nz/sather/



February 12, 2003
Hi, Daniel.

The Sather itterators seem less powerful.  With the loop functions illustrated below, it's possible to eliminate one of the most common need for function pointers in C: passing callbacks to complex data traversal routines.

With this itterator syntax, you could create itterators that traverse binary trees, doing the loop body for each node.  The code is easy to write and read.  Doing this in Sather is comparitively ugly, and less efficient.

Bill

Daniel Yokomiso wrote:
> In article <b1nrjp$1032$1@digitaldaemon.com>, Bill Cox says...
> 
>>Hi.
>>
>>I've been playing with foreach itterator syntax a bit.  This mechanism is
>>complex, but very nice to use.  If it's not too complex to implement, I think it
>>might be a nice enhancement to D.
>>
>>Here's how it works.  In a container class, or any class that needs an itterator
>>over children, define a loop function.  Here's an example for directed graphs:
>>
>>class Node {
>>Edge firstIn, firstOut;
>>// This itterates through in edges
>>loop inEdges(Edge edge) {
>>for(edge = firstIn; edge != null; edge = edge.nextInEdge) {
>>doloop;
>>}
>>}
>>// This itterates through out edges
>>loop outEdges(Edge edge) {
>>for(edge = firstOut; edge != null; edge = edge.nextOutEdge) {
>>doloop;
>>}
>>}
>>// This itterates through all edges
>>loop edges(Edge edge) {
>>foreach(inEdges, edge) {
>>doloop;
>>}
>>foreach(outEdges, edge) {
>>doloop;
>>}
>>}
>>}
>>
>>The foreach loops specify a loop function, and a loop variable.  The compiler
>>can inline the loop functions to generate the expected code
>>
>>Bill
>>
>>
> 
> 
> It looks very similar to Sather iterators, but less powerful, because it can
> iterate only over one iterator. There's some useful info at: http://www.icsi.berkeley.edu/~sather/Documentation/IteratorTutorial/
> http://www.icsi.berkeley.edu/~sather/index.html
> http://www.cs.waikato.ac.nz/sather/
> 
> 
> 

February 14, 2003
Hi,

Comments embedded:

In article <3E4A81F1.6080300@viasic.com>, Bill Cox says...
>
>Hi, Daniel.
>
>The Sather itterators seem less powerful.  With the loop functions illustrated below, it's possible to eliminate one of the most common need for function pointers in C: passing callbacks to complex data traversal routines.
>
>With this itterator syntax, you could create itterators that traverse binary trees, doing the loop body for each node.  The code is easy to write and read.  Doing this in Sather is comparitively ugly, and less efficient.
>
>Bill
>

I don't understand your remarks about Sather-like iterators being "less powerful" or "ugly". Here's your code written using Sather-like iterating constructs (I'm mixing Sather and D syntax):

class Node {
Edge firstIn, firstOut;
// note that ! marks a method as an iterator
Edge inEdges!() {
Edge edge = firstIn;
// while isn't a primitive but a iterator too
loop while!(edge != null);
yield edge;
edge = edge.nextInEdge
end
}
Edge outEdges!() {
Edge edge = firstOut;
loop while!(edge != null);
yield edge;
edge = edge.nextOutEdge
end
}
Edge edges!() {
loop
yield inEdges!();
end
loop
yield outEdges!();
end
}
}

Iterators can be used to yield values of series:

int fibs!() {
int a = 0;
int b = 1;
loop
yield a;
(a, b) = (b, a + b); // tuple construction/deconstruction is nice ;-)
end
}

They can also be combined in several ways. More than one iterator can be used in the same loop, and the first to end will terminate the loop. There's also input iterators, like:

class List {
Object get!() {
int i = 0;
loop while!( i < size());
yield get(i);
i++;
end
}
void set!(Object value) {
int i = 0;
loop while!( i < size());
set(i, value);
yield;
i++;
end
}
void copy(List other) {
loop
set!(other.get!()); // ends when either get! or set! quits
end
}
void copyFiltering(List other, bit (*predicate)(Object)) {
loop
Object value = other.get!();
if (predicate(value)) {
set!(value); // not all iterators in the loop
// are called every iteration
}
end
}
}

Your foreach syntax is very similar to CLU, which was the base for Sather iterators, but they went beyond it. There are lots of good iterator examples available and AFAIK they can be compiled to efficient assembly.

>Daniel Yokomiso wrote:
>> In article <b1nrjp$1032$1@digitaldaemon.com>, Bill Cox says...
>> 
>>>Hi.
>>>
>>>I've been playing with foreach itterator syntax a bit.  This mechanism is complex, but very nice to use.  If it's not too complex to implement, I think it might be a nice enhancement to D.
>>>
>>>Here's how it works.  In a container class, or any class that needs an itterator over children, define a loop function.  Here's an example for directed graphs:
>>>
>>>class Node {
>>>Edge firstIn, firstOut;
>>>// This itterates through in edges
>>>loop inEdges(Edge edge) {
>>>for(edge = firstIn; edge != null; edge = edge.nextInEdge) {
>>>doloop;
>>>}
>>>}
>>>// This itterates through out edges
>>>loop outEdges(Edge edge) {
>>>for(edge = firstOut; edge != null; edge = edge.nextOutEdge) {
>>>doloop;
>>>}
>>>}
>>>// This itterates through all edges
>>>loop edges(Edge edge) {
>>>foreach(inEdges, edge) {
>>>doloop;
>>>}
>>>foreach(outEdges, edge) {
>>>doloop;
>>>}
>>>}
>>>}
>>>
>>>The foreach loops specify a loop function, and a loop variable.  The compiler can inline the loop functions to generate the expected code
>>>
>>>Bill
>>>
>>>
>> 
>> 
>> It looks very similar to Sather iterators, but less powerful, because it can iterate only over one iterator. There's some useful info at: http://www.icsi.berkeley.edu/~sather/Documentation/IteratorTutorial/ http://www.icsi.berkeley.edu/~sather/index.html http://www.cs.waikato.ac.nz/sather/
>> 
>> 
>> 
>

Best regards,
Daniel Yokomiso.