www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Empowering foreach with in-place iteration

reply "Janice Caron" <caron800 googlemail.com> writes:
There are some things that iterators can do that foreach can't. I
/don't/ want to add iterators to D. Instead, I'd like to see foreach
enhanced, so that it can do the things it currently can't.

Here's my second example.

 string unescape(string s)
 {
     string r;
     for (int i=0; i<s.length; ++i)
     {
         if (s[i] == '\')
         {
             ++i;
             if (i == s.length) break;
             r ~= f(s[i]);
         }
         else
         {
             r ~= s[i];
         }
     }
     return r;
 }

How much nicer it would be to be able to write this as:

 string unescape(string s)
 {
     string r;
     for (char c; s)
     {
         if c == '\')
         {
             iterate(s); /* advances one step through s; modifies c */
             r ~= f(c);
         }
         else
         {
             r ~= c;
         }
     }
     return r;
 }

I'd also like to be able to advance by n steps, not necessarily just
one. That could be done with something like iterate(s,n). For that
matter, I'd also like to go backwards, so it would be great if n could
be negative.

Of course there are some subtleties to consider. What happens if we
reach beyond the end of the array (or the beginning, if we go
backwards)? Is it sufficient to act like break, as in my example
above? Or should that throw an exception? I don't really mind which
behavior is chosen. Either way, I'd still like the feature.
Sep 09 2007
next sibling parent Daniel Keep <daniel.keep.lists gmail.com> writes:
Again, this would be tricky to do.  Since the body of a loop is a
function, you can't call into it at a specific place.  It's also not
something that crops up very often.

Perhaps a better alternative might be to try for generators; that
(possibly combined with some kind of special aggregate declaration)
might solve the problem.

 string unescape(string s)
 {
     string r;
     foreach( c ; aggregate = s.iter )
     {
         if c == '\')
         {
             c = aggregate.next;
             r ~= f(c);
         }
         else
         {
             r ~= c;
         }
     }
     return r;
 }

As a bonus, this would make writing custom aggregates much easier, and
possibly allow for easier implementation of lockstep iteration.

On a side note, my PullDOM implementation actually allows for exactly
this sort of behaviour, so it's certainly something you can do right
now; you just need to construct the aggregate appropriately.

	-- Daniel
Sep 09 2007
prev sibling parent BCS <ao pathlink.com> writes:
Reply to Janice,

 There are some things that iterators can do that foreach can't. I
 /don't/ want to add iterators to D. Instead, I'd like to see foreach
 enhanced, so that it can do the things it currently can't.
 
 Here's my second example.
 
 string unescape(string s)
 {
   string r;
   foreach (char c; s)
   {
     if c == '\')
     {
        iterate(s); /* advances one step through s; modifies c */
        r ~= f(c);
     }
     else
     {
       r ~= c;
     }
   }
   return r;
 }

The iterate could be done by putting a pointer (and most of the local variables) in the stack frame outside the foreach and having the iterate actually be a "store next op in ptr, return" and then placing a goto ptr at the start of the function. this would let the function return and resume at the same point on the next call (this is something like a generator I think). languages support needed big time.
Sep 09 2007