RBTree delegates and types

Viktor viktor.ivanov at gmail.com
Mon Mar 19 09:16:39 UTC 2018


On Sunday, 18 March 2018 at 17:21:58 UTC, Steven Schveighoffer 
wrote:
> On 3/18/18 8:34 AM, Viktor wrote:
>> Hey,
>> 
>> I'm trying to convert an old legacy app to D and have a couple 
>> of questions. It has been a very fun weekend!
>> 
>> First, I could not make std.container.rbtree use a delegate 
>> for a comparator. The docs say it should be possible, but I 
>> got a weird error.
>> 
>> I tracked it down to RedBlackTreee.opEquals() using explicit 
>> function when calling equals():
>> 
>> return equal!(function(Elem a, Elem b) => !_less(a,b) && 
>> !_less(b,a))(thisRange, thatRange);
>> 
>> When I removed the "function" things started compiling (I have 
>> yet to test the code due to question #2 below). I've done a 
>> dub -b unittest without issues so it might be OK.
>> 
>> So, the first...several questions are: do you think this 
>> change is safe and should I raise an issue in the bugzilla or 
>> do a PR for it on github?
>
> Yes, seems like an oversight. RedBlackTree.opEquals was added 
> almost 6 years ago, and it's possible this wouldn't have worked 
> back then (https://github.com/dlang/phobos/pull/900)
>
>
>> Should it include a new unittest that makes sure rbtree can be 
>> instantiated with a delegate?
>
> Definitely. Thanks for thinking of this!
>
>> 
>> The other part I'm still struggling with is about auto types. 
>> Can I store the rbtree type in the following class so it can 
>> be used from another method?
>> 
>> class Indexer(T, alias pred)
>> {
>       alias RBType = RedBlackTree!(uint, (a, b) => comp(a, b));
>>     this(T storage)
>>     {
>>        this.storage = storage;
>
>          this.index = new RBType();
>
>>     }
>
>> 
>>     void dumpIndex()
>>     {
>>         // how to get my dirty hands on the index here?
>
>           // answer: just use it?
>
>>     }
>> 
>>     bool comp(uint i1, uint i2)
>>     {
>>        auto rec1 = storage[i1];
>>        auto rec2 = storage[i2];
>>        return pred(rec1, rec2);
>>     }
>> 
>>     private T storage;
>
>       RBType index;
>
>> }
>> 
>
> -Steve

Hi Steve, thanks for replying!

I've also noticed that RedBlackTree.opEquals() is like this from 
the initial pull request and was wondering if noone has been 
using a delegate and why...

On the second topic, I've tried that and it doesn't work. I have 
a minimal test program that shows the issue.

https://run.dlang.io/is/WNF78H

onlineapp.d(15): Error: need this for less of type bool(int a, 
int b)
onlineapp.d(15):        instantiated from here: Generic!((a, b) 
=> less(a, b))

If I try using an explicit delegate in the alias:

onlineapp.d(15): Error: delegate `onlineapp.Custom.__dgliteral6` 
cannot be class members
onlineapp.d(15):        instantiated from here: Generic!(delegate 
(a, b) => less(a, b))

That seems reasonable to me, since the delegate needs a frame 
(for the this pointer) and there is no frame at that point.

I think in the end I'll need to plant an interface that RBTree 
will implement and use the interface instead.

The code in question:

class Generic(alias pred)
{
    void add(int a, int b)
    {
        import std.stdio : writeln;
        if (pred(a,b))
            writeln(a);
        else
            writeln(b);
    }
}

class Custom
{
     alias MyGeneric = Generic!( (a,b) => less(a,b) );
     private MyGeneric g;

     this ()
     {
         g = new MyGeneric;
     }

     void test()
     {
         g.add(5, 6);
     }

     bool less(int a, int b)
     {
         import std.stdio : writeln;
         writeln("Yup");
         return a < b;
     }
}

void main()
{
     auto t = new Custom;
     t.test;
}


More information about the Digitalmars-d-learn mailing list