www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - "+=" (overloads) with custom array slices on both lhs, and rhs ??

reply james.p.leblanc <james.p.leblanc gmail.com> writes:
Dear D-ers,

I have constructed a custom array type that works, but is missing
correct functioning on some operator overloads.

The stripped down minimum example (module) was over 100 lines (due
overloading opAssign, etc.) Probably too long to be a good forum 
post.

However, a short main may explain the issue succinctly (at end).

In words: the standard D static arrays, and dynamic array can do a
"vector accumulation" using:

```d
f += g;
```

We can even have slices on both lhs and rhs:

```d
f[ 2 .. 5 ] += g[ 4 .. 7 ];
```

So, this **should** be possibly for custom array types.  I have
looked at opIndexOpAssign, and learned a great deal from Michael
Parkers book on the use of opSlice, etc. with overloads.  Also, I 
have
searched for clues in the dmd source code ... but it was not
easy to perceive how this is done.

Here is an ugly code example (without module code -- so maybe 
useless).

How does one overload custom types with "+=" and slices on both 
left and right?

Thanks in advance,
James

**compilation error message appear as comments to right of 
offending lines**

==============================================================
```d
import std.stdio;
import myarray_mod;

void main(){

    // static arrays
    int[7] x = [ 10, 11, 12, 13, 14, 15, 16 ];
    int[7] y = [ 100, 101, 102, 103, 104, 105, 106 ];

    // custom "arrays"
    auto f = myArray( x.ptr, 7 );
    auto g = myArray( y.ptr, 6 );

    f[ 1 ] += 909;           // accumulating a scalar works fine


    f[] += 909;              // "f.opIndex() is not an lvalue and 
cannot be modified
    f += g;                  // f is not a scale is is a myArray
    f[ 2 .. 5 ]+=g[ 2 .. 5]; //f.opIndex(f.opSlice(2LU, 5LU ... 
(possible missing[])

    // for standard dynamic arrays, this works fine
    int[] a = [ 1, 2, 3, 4, 5, 6 ];
    int[] b = [ 4, 5, 6, 7, 8, 9 ];
    writeln("a: ", a);
    writeln("b: ", b);
    a[ 1 .. 4 ] += b[ 2 .. 5 ];  // even with slices on both lhs & 
rhs!!
    writeln("a: ", a);

    return;
}

```
Sep 05 2021
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Sunday, 5 September 2021 at 19:43:20 UTC, james.p.leblanc 
wrote:
 Dear D-ers,

 I have constructed a custom array type that works, but is 
 missing
 correct functioning on some operator overloads.
[...]
 ```d
 import std.stdio;
 import myarray_mod;
 ```
Please post the source code for `myarray_mod` so that we can reproduce the errors you're seeing.
Sep 05 2021
parent reply james.p.leblanc <james.p.leblanc gmail.com> writes:
On Sunday, 5 September 2021 at 20:38:29 UTC, Paul Backus wrote:
 On Sunday, 5 September 2021 at 19:43:20 UTC, james.p.leblanc 
 wrote:
 Dear D-ers,

 I have constructed a custom array type that works, but is 
 missing
 correct functioning on some operator overloads.
[...]
 ```d
 import std.stdio;
 import myarray_mod;
 ```
Please post the source code for `myarray_mod` so that we can reproduce the errors you're seeing.
Hello Paul, Thanks for having a look ... James ```d module myArray_mod; import std.stdio; struct myArray{ int* ptr; size_t length; this( int* ptr, size_t length){ this.ptr = ptr; this.length = length; } myArray opIndex(){ return this; } int opIndex(size_t i){ return ptr[i]; } int[] opIndex( SliceInfo info ){ return ptr[ info.start .. info.end ]; } void opIndexAssign(int val, size_t i){ ptr[i] = val; return; } void opIndexAssign(int val, SliceInfo info){ auto ctr=0; foreach( i ; info.start .. info.end ){ ptr[i] = val; } return; } void opIndexAssign(int[] val, SliceInfo info){ auto ctr=0; foreach( i ; info.start .. info.end ){ ptr[i] = val[ctr++]; } return; } // =========================================================== void opIndexOpAssign(string op)(int val, int ind){ writeln("opIndexOpAssign with INTEGER"); if( (op == "+") || (op == "-") || (op == "*") || (op == "/") ){ mixin(" ptr[ind] " ~ op ~ "= val;"); } return; } void opIndexOpAssign(string op)(int val, SliceInfo info){ writeln("opIndexOpAssign with SLICE"); if( (op == "+") || (op == "-") || (op == "*") || (op == "/") ){ foreach( i ; 0 .. length ){ mixin(" ptr[i] " ~ op ~ "= val;"); } } return; } void opIndexOpAssign(string op)(SliceInfo rhs, SliceInfo lhs){ writeln("opIndexOpAssign with LHS SLICE and RHS SLICE "); if( (op == "+") || (op == "-") || (op == "*") || (op == "/") ){ foreach( i ; 0 .. length ){ mixin(" ptr[i] " ~ op ~ "= 1;"); } } return; } myArray opBinary(string op)(myArray rhs){ writeln("opBinary"); if( (op == "+=") || (op == "-=") || (op == "*=") || (op == "/=") ){ foreach( i ; 0 .. length ){ mixin(" ptr[i] " ~ op ~ " rhs.ptr[i];"); } } return; } struct SliceInfo{ size_t start, end; } SliceInfo opSlice(size_t dim)(size_t start, size_t end){ return SliceInfo(start, end); } void toString(scope void delegate(const(char)[]) sink) const { import std.format; sink("["); foreach( i ; 0 .. length ){ formattedWrite( sink, "%s", ptr[i] ); if( i< length-1 ) sink(", "); } sink("]"); } } ```
Sep 05 2021
parent reply jfondren <julian.fondren gmail.com> writes:
On Sunday, 5 September 2021 at 20:49:08 UTC, james.p.leblanc 
wrote:
 On Sunday, 5 September 2021 at 20:38:29 UTC, Paul Backus wrote:
 Please post the source code for `myarray_mod` so that we can 
 reproduce the errors you're seeing.
Hello Paul, Thanks for having a look ... James
Here's a reduction of your myArray.d that works with your unchanged usage code: ```d module myArray; import std.stdio; struct myArray { int* ptr; size_t length; myArray opIndex() { return this; } int opIndex(size_t i) { return ptr[i]; } void opIndexOpAssign(string op)(int val, int ind) { if ((op == "+") || (op == "-") || (op == "*") || (op == "/")) { mixin(" ptr[ind] " ~ op ~ "= val;"); } } myArray opSlice(size_t start, size_t end) { return myArray(&ptr[start], end - start); } void opOpAssign(string op)(int rhs) if (op == "+") { foreach (i; 0 .. length) { mixin("ptr[i] " ~ op ~ "= i;"); } } void opOpAssign(string op)(myArray rhs) if (op == "+") { foreach (i; 0 .. length) { mixin("ptr[i] " ~ op ~ "= rhs.ptr[i];"); } } } ```
Sep 05 2021
parent james.p.leblanc <james.p.leblanc gmail.com> writes:
On Sunday, 5 September 2021 at 21:25:06 UTC, jfondren wrote:
 On Sunday, 5 September 2021 at 20:49:08 UTC, james.p.leblanc 
 wrote:
 Here's a reduction of your myArray.d that works with your 
 unchanged usage code:

 ```d
 module myArray;
 import std.stdio;

     void opOpAssign(string op)(myArray rhs) if (op == "+") {
         foreach (i; 0 .. length) {
             mixin("ptr[i] " ~ op ~ "= rhs.ptr[i];");
         }
     }

 ```
Wow, these quick and helpful replies are gratefully received! They have helped me learn many new aspects of D (especially the overloading!) Serious thanks to **all**. Best Regards, James
Sep 05 2021
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 9/5/21 12:43 PM, james.p.leblanc wrote:

 I have constructed a custom array type that works, but is missing
 correct functioning on some operator overloads.
With its old, new, and newest styles; and support for multi-dimensional use cases; operator overloading can be difficult to get right. Here is a one-dimensional case that works: struct MyArray(T) { T[] elements; this(size_t length) { this.elements.length = length; } size_t opDollar() const { return elements.length; } auto opSliceOpAssign(string op)(T value, size_t beg, size_t end) { auto slice = elements[beg .. end]; mixin (format!q{ slice[] %s= value; }(op)); return slice; } // For the entire range of elements auto opSliceOpAssign(string op)(T value) { // Dispatch to the other one return this.opSliceOpAssign!op(value, 0, elements.length); } } import std.stdio; import std.format; void main() { auto m = MyArray!(int)(10); m[2 .. 5] += 42; writeln(m); m[4 .. $] -= 100; writeln(m); m[] *= 2; writeln(m); } Ali
Sep 05 2021
parent james.p.leblanc <james.p.leblanc gmail.com> writes:
On Sunday, 5 September 2021 at 21:06:49 UTC, Ali Çehreli wrote:
 On 9/5/21 12:43 PM, james.p.leblanc wrote:
   m[4 .. $] -= 100;
   writeln(m);

   m[] *= 2;
   writeln(m);
 }

 Ali
Ali, Thanks for your example code ... I have much to learn from this and will need to study it tomorrow when I am fresh. I hope that I will see how to extend this so that it can do slices on both the left side and right side ... for example: ```d m[ 4 .. 8 ] += q[ 7 .. 11 ]; ``` Best Regards, James
Sep 05 2021