www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Defining an alias to an overloaded function

reply olvy <olvy olvy.ol> writes:
I'm learning D, and as an exercise, I'm trying to define a 
HashSet that would be a wrapper around an associative array with 
some dummy value type.

This worked fine until I've tried writing opSlice for this 
HashSet in terms of the byKey() function of the AA.  I defined my 
own internal type that wraps the one returned by byKey and 
returned it.  However I had to keep byKey's result inside my 
internal type, but I couldn't figure out how to name it properly 
without getting a compilation error.

The problem is that byKey is overloaded and but I can't figure 
out how to convince the compiler to disambiguate between the 
overloads.

Another lesser problem is that I have to write "opSlice" 
explicitly at the call site instead of using [].   But it might 
be that the compiler is confused due to failure of parsing the 
function.

My aim isn't building a HashSet, the point is learning, here 
specifically learning how to convince the compiler to use the 
correct byKey overload in this case.
I could also trivially use the AA's keys() function to implement 
opSlice.  But I like byKey since it exposes just an iterator, 
while keys() actually allocates an array which isn't necessary 
here.

I'm using dmd 2.089 on my machine.

My code is (also in https://wandbox.org/permlink/zXsf7sQiKDj6zjlJ)

import std;

struct HashSet(T) {
     int[T] _dict;

     bool add(T val) {
         auto prev = val in _dict;
         _dict[val] = 0;
         return prev is null;
     }

     bool remove(T val) {
         return _dict.remove(val);
     }

     bool opBinaryRight(string op)(T val) {
         static if (op == "in") {
             return (val in _dict) !is null;
         } else {
             static assert(false, "Operator " ~ op ~ " not 
implemented");
         }
     }

     import std.traits;
     import std.meta;
     struct RangeImpl(T) {
         // Next line has compilation error since byKey has 2 
overloads
         alias byKeyAlias = Alias!(byKey!(int[T])(T.init));
         ReturnType!(byKeyAlias) keyRange;
         // alias byKeyAlias = byKey;
         // ReturnType!(byKey!(int[T], T, int)) keyRange;
         this(ref int[T] d) {
             keyRange = d.byKey();
         }
         bool empty() const {
             return keyRange.empty;
         }
         ref T front() {
             return keyRange.front;
         }
         void popFront() {
             keyRange.popFront();
         }
     }

     // T[] opSlice(T)() {
     //     return _dict.keys;
     // }

     RangeImpl!T opSlice(T)() {
         return RangeImpl!T(_dict);
     }

}

void main()
{
     HashSet!long h;
     h.add(0);
     h.add(1);
     if (1 in h) {
         writeln("it is");
     }
     if (h.opSlice!long.all!(nn => nn < 5)) {
         writeln("less than 5");
     }
}
Jan 20 2020
parent reply Boris Carvajal <boris2.9 gmail.com> writes:
On Monday, 20 January 2020 at 22:02:54 UTC, olvy wrote:
 I'm learning D, and as an exercise, I'm trying to define a 
 HashSet that would be a wrapper around an associative array 
 with some dummy value type.
This seems to work: ... struct RangeImpl(T) { alias byKeyRetType = typeof(byKey!(int[T])((int[T]).init)); byKeyRetType keyRange; this(ref int[T] d) { keyRange = d.byKey; } bool empty() { return keyRange.empty; } ... } RangeImpl!T opSlice() { return RangeImpl!T(_dict); } } void main() { ... if (h[].all!(nn => nn < 5)) { writeln("less than 5"); }
Jan 20 2020
parent olvy <olvy olvy.ol> writes:
On Tuesday, 21 January 2020 at 04:44:43 UTC, Boris Carvajal wrote:
 This seems to work:

 ...
     struct RangeImpl(T) {
         alias byKeyRetType = 
 typeof(byKey!(int[T])((int[T]).init));
         byKeyRetType keyRange;
         this(ref int[T] d) {
             keyRange = d.byKey;
         }
         bool empty() {
             return keyRange.empty;
         }
         ...
     }

     RangeImpl!T opSlice() {
         return RangeImpl!T(_dict);
     }
 }

 void main()
 {
     ...
     if (h[].all!(nn => nn < 5)) {
         writeln("less than 5");
     }
Thank you very much! I have completely forgotten about typeof(). I see you also fixed my unnecessary (T) template parameter to opSlice, which also caused a compilation error in addition to the first mistake. I think this is because it "shadows" the original T parameter from the struct itself, right?
Jan 23 2020