Passing $ as a function argument

Simen Kjærås simen.kjaras at gmail.com
Tue Oct 16 12:20:43 UTC 2018


On Sunday, 14 October 2018 at 15:27:07 UTC, Michael Coulombe 
wrote:
> On Sunday, 14 October 2018 at 14:35:36 UTC, lngns wrote:
>> On Sunday, 14 October 2018 at 13:18:37 UTC, lngns wrote:
>>> That would require introducing a new type
>>
>> Or just use int with a negative number... That's how it's done 
>> in some dynamic languages.
>> But my point is that it should be compatible with pre-existing 
>> code using unsigned indices somehow. I don't think that is 
>> possible.
>
> Another way to do this with UFCS:
>
> // write-once library wrapper
> struct Indexer(R) {
>     R r;
>     auto opDollar() { return r.length; }
>     auto opIndex(size_t i) { return r[i]; }
> }
> auto indexer(R)(R r) { return Indexer(r); }
>
> // rewrite index parameter => return wrapped range
> auto foo()
> {
>     auto arr = (...);
>     return indexer(arr);
> }
>
> // easy-to-use result
> auto end = foo[$-1];

Didn't feel like making a full expression tree thing, so feel 
free to extend this:

struct Index {
     struct Op {
         string op;
         int value;
         void apply(ref size_t val) {
             switch (op) {
                 case "+": val += value; break;
                 case "-": val -= value; break;
                 case "*": val *= value; break;
                 case "/": val /= value; break;
                 case "%": val %= value; break;
                 default: assert(false);
             }
         }
     }
     Op[] ops;
     bool fromEnd;
     this(bool b) { fromEnd = b; }
     this(size_t i) {
         ops ~= Op("+", i);
     }
     static Index opDollar() {
         return Index(true);
     }
     static Index opIndex(Index idx) {
         return idx;
     }
     static Index opIndex(size_t idx) {
         return Index(idx);
     }
     auto opBinary(string op)(int rhs) {
         Index result = this;
         result.ops ~= Op(op, rhs);
         return result;
     }
     auto value(size_t length) {
         size_t result = fromEnd ? length : 0;
         foreach (e; ops)
             e.apply(result);
         return result;
     }
}

struct Indexer(R) {
     R r;
     alias r this;
     Index opDollar() {
         return Index(true);
     }
     auto opIndex(Index idx) {
         return r[idx.value(r.length)];
     }
     auto opIndex(size_t idx) {
         return r[idx];
     }
}

auto indexer(R)(R r) {
     return Indexer!R(r);
}

unittest {
     auto a = Index[$-2]; // Will always point to next-to-last 
element.
     auto arr = [1,2,3,4,5,6,7,8,9].indexer; // Wrap access.
     assert(arr[0] == 1); // Regular access still works.
     assert(arr[a] == 8); // Look ma, I'm using $!
     assert(arr[Index[$-1]] == 9); // Look ma, I'm using $!
}

--
   Simen


More information about the Digitalmars-d mailing list