www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - adding delegate to opApply

reply berni <someone somewhere.com> writes:
I've tried to make a small example, but it's not easy to get this 
reduced further. At least I didn't manage. The following program 
can also be found at https://run.dlang.io/is/p6l7xN

void main()
{
     auto foo = Ways([Way([8,2,3,0]),Way([4,6,2]),Way([4,7,2,6])]);

     foo.remove_odds();

     assert(foo==Ways([Way([8, 2]), Way([4, 6, 2]), Way([4]), 
Way([0]), Way([2, 6])]));
}

struct Ways
{
     Way[] ways;

     void remove_odds()
     {
         Way[] new_ways;

         foreach (ref way;ways)
             foreach (point, void delegate(void delegate(Way way)) 
remove;way)
                 if (point%2==1)
                     remove(delegate(Way way) {new_ways ~= way;});

         ways ~= new_ways;
     }
}

struct Way
{
     int[] points;

     auto opApply(int delegate(int, void delegate(void 
delegate(Way way))) work)
     {
         size_t[] remove;
         void delegate(Way) add_new_way;

         foreach (index,point;points)
             if (auto result=work(point,(void delegate(Way) 
anw){remove~=index; add_new_way=anw;}))
                 return result;

         import std.algorithm.sorting: sort;
         foreach (index;remove.sort!("a>b"))
         {
             add_new_way(Way(points[index+1..$]));
             points = points[0..index];
         }

         return 0;
     }
}

I need to pass the delegate add_new_way somehow to opApply. Here 
I managed this, by adding this delegate to the remove-delegate 
and safe it away for further use. This works, because if remove 
is never called, add_new_way is not used either. But it's a 
little bit awkward. Is there a better way, to achieve this? (Note 
1: In the real world, point%2==1 is a more complex function call. 
Note 2: The order of elements in Way[] way doesn't matter, if 
that makes things easier.)

Maybe it's possible to work with something like 
std.algorithm.iteration.splitter instead of those loops and 
opApply. But splitter takes an element or a range, not a 
predicate.
Sep 02 2019
parent reply Paul Backus <snarwin gmail.com> writes:
On Monday, 2 September 2019 at 12:43:31 UTC, berni wrote:
 I need to pass the delegate add_new_way somehow to opApply. 
 Here I managed this, by adding this delegate to the 
 remove-delegate and safe it away for further use. This works, 
 because if remove is never called, add_new_way is not used 
 either. But it's a little bit awkward. Is there a better way, 
 to achieve this? (Note 1: In the real world, point%2==1 is a 
 more complex function call. Note 2: The order of elements in 
 Way[] way doesn't matter, if that makes things easier.)
The delegate that gets passed to opApply is constructed from the body of the foreach loop; you don't (normally) pass it explicitly. If you have an existing delegate that you want to use with opApply, the easiest way is like this: void delegate(Thing) myDelegate = ...; foreach(thing; things) { myDelegate(thing); } // Equivalent to: things.opApply((Thing t) => myDelegate(t))
Sep 02 2019
parent berni <someone somewhere.com> writes:
On Monday, 2 September 2019 at 14:20:11 UTC, Paul Backus wrote:

 If you have an existing delegate that you want to use with 
 opApply, the easiest way is like this:

 void delegate(Thing) myDelegate = ...;

 foreach(thing; things) {
     myDelegate(thing);
 }
 // Equivalent to: things.opApply((Thing t) => myDelegate(t))
Thanks for your answer. It's not exactly, what I was looking for, but meanwhile I think, the whole idea was not reasonable. I meanwhile returned to using a normal function call instead of opApply, which makes it easy to pass a delegate as one of the parameters.
Sep 03 2019