opSlice() or opIndex() for the entire slice?

Ali Çehreli via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Thu Sep 4 14:50:24 PDT 2014


On 09/04/2014 12:19 PM, "Marc Schütz" <schuetzm at gmx.net>" wrote:
> On Thursday, 4 September 2014 at 19:12:27 UTC, Ali Çehreli wrote:
>> The documentation says "To overload a[], simply define opIndex with no
>> parameters":
>>
>>   http://dlang.org/operatoroverloading.html#Slice
>>
>> And it works with some uses of a[]. However, opSlice() seems to be
>> needed to actually use the returned slice further.
>>
>> Note that opSlice() also seems to be for backward compatibility: "For
>> backward compatibility, a[] and a[i..j] can also be overloaded by
>> implementing opSlice() with no arguments and opSlice(i, j) with two
>> arguments, respectively. This only applies for one-dimensional
>> slicing, and dates from when D did not have full support for
>> multidimensional arrays. This usage of opSlice is discouraged."
>>
>> How can I achieve the last line in main() without needing opSlice()? I
>> am trying to let the Slice type handle opAssign() and friends.
>>
>
> --8<-- snip --8<--
>
>>     // This requires opSlice.
>>     c[] = 42;
>> }
>
> Have you tried opIndexAssign()?

That works and kind of makes sense.

My main confusion stems from the fact that the new templated opSlice() 
does not have its own section on the documentation page, other than 
appearing in examples of other operators.

What I did not like about opIndexAssign() at first is the fact that it 
puts the Collection in the middle and requires an explicit dispatch by 
the programmer to Slice. In contrast, the legacy way (which still works) 
bypasses Collection and goes directly to Slice.

However, the legacy way supports only one dimension.

Also, the new way is necessary as the same function (namely, 
opIndexAssign) takes care of both indexing and slicing. This is from the 
change log:

     void opIndexAssign(A...)(E val, A indices)
     {
         assert(A.length == payload.length);

         foreach (dim, x; indices)
         {
             static if (is(typeof(x) : size_t))
             {
                 // this[..., x, ...]
                 payload[dim][x] = val;
             }
             else
             {
                 // this[..., x[0] .. x[1], ...]
                 payload[dim][x[0] .. x[1]] = val;
             }
         }
     }

So, the following is my current solution. Note that opIndex() seems 
still be necessary. Is it possible to replace it with an opSlice overload?

import std.stdio;

struct Collection
{
     int[] elements;

     /* Handles the slice operations */
     struct Slice
     {
         int[] slice;

         Slice opAssign(int value)
         {
             writefln("Slice.opAssign(int)");
             slice[] = value;
             return this;
         }
     }

     size_t opDollar() const
     {
         writefln("opDollar()");
         return elements.length;
     }

     // CHALLENGE: Can you replace this with an opSlice overload?
     Slice opIndex()
     {
         writefln("opIndex()");
         return Slice(elements);
     }

     Slice opSlice(size_t dim, A...)(A args)
     {
         writefln("opSlice!%s(%(%s, %))", dim, [ args ]);
         return Slice(elements[args[0] .. args[1]]);
     }

     Collection opIndexAssign(A...)(int value, A indexes)
     {
         writefln("opIndexAssign(%s, %(%s, %))", value, [ indexes ]);

         foreach (dim, x; indexes)
         {
             static if (is(typeof(x) : size_t))
             {
                 elements[x] = value;

             } else static if (is(typeof(x) : Slice)) {
                 x = value;

             } else {
                 static assert(false);
             }
         }

         return this;
     }
}

void main()
{
     auto c = Collection([ 0, 1, 2, 3]);

     writeln("\n--- c[] ---");
     c[];

     writeln("\n--- c[1 .. $-1] = 42 ---");
     c[1 .. $-1] = 42;

     writeln("\n--- c[3] = 100 ---");
     c[3] = 100;

     assert(c.elements == [ 0, 42, 42, 100 ]);
}

The output:

--- c[] ---
opIndex()

--- c[1 .. $-1] = 42 ---
opDollar()
opSlice!0(1, 3)
opIndexAssign(42, Slice([1, 2]))
Slice.opAssign(int)

--- c[3] = 100 ---
opIndexAssign(100, 3)

Ali



More information about the Digitalmars-d-learn mailing list