Thread overview
adding delegate to opApply
Sep 02, 2019
berni
Sep 02, 2019
Paul Backus
Sep 03, 2019
berni
September 02, 2019
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.
September 02, 2019
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))
September 03, 2019
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.