digitalmars.D.learn - Array operations with array of structs
- Peter (27/27) Jul 05 2015 Hi,
- Nicholas Wilson (9/36) Jul 05 2015 you need to define the slice operators. e.g.
- Nicholas Wilson (16/63) Jul 05 2015 whoops. it may be complaining about lack of opSliceAssign
- anonymous (5/29) Jul 06 2015 `f`, `c`, and `d` are arrays though, not `Vector3`s. The code
- anonymous (3/30) Jul 06 2015 Works for me with various versions of dmd on linux. What compiler
Hi, I have a struct with arithmetic operations defined using opBinary but array operations with arrays of it don't work. struct Vector3 { public double[3] _p; ... Vector3 opBinary(string op)(in Vector3 rhs) const if (op == "+"){ Vector3 result; result._p[] = this._p[] + rhs._p[]; return result; } ... } unittest{ auto a = Vector3([2.0, 2.0, 0.0]); auto b = Vector3([1.0, 2.0, 1.0]); Vector3[] c = [a]; Vector3[] d = [b]; Vector3 e = a + b; // works Vector3[] f; f[] = c[] + d[]; // Error: invalid array operation 'f[] = c[] + d[]' because Vector3 doesn't support necessary arithmetic operations } how can I get this to work? Thanks
Jul 05 2015
On Monday, 6 July 2015 at 01:16:54 UTC, Peter wrote:Hi, I have a struct with arithmetic operations defined using opBinary but array operations with arrays of it don't work. struct Vector3 { public double[3] _p; ... Vector3 opBinary(string op)(in Vector3 rhs) const if (op == "+"){ Vector3 result; result._p[] = this._p[] + rhs._p[]; return result; } ... } unittest{ auto a = Vector3([2.0, 2.0, 0.0]); auto b = Vector3([1.0, 2.0, 1.0]); Vector3[] c = [a]; Vector3[] d = [b]; Vector3 e = a + b; // works Vector3[] f; f[] = c[] + d[]; // Error: invalid array operation 'f[] = c[] + d[]' because Vector3 doesn't support necessary arithmetic operations } how can I get this to work? Thanksyou need to define the slice operators. e.g. auto opSlice() // no parameters to get whole slice eg. a[] // can also define with opSlice(size_t i, size_t j) // for access like a[ i .. j] { return _p; }
Jul 05 2015
On Monday, 6 July 2015 at 03:02:59 UTC, Nicholas Wilson wrote:On Monday, 6 July 2015 at 01:16:54 UTC, Peter wrote:whoops. it may be complaining about lack of opSliceAssign i.e. `f[] =` again define this with no parameters for the whole slice or two for a[i .. j] = also note that you need to give memory for this array assignment to go. eg.Hi, I have a struct with arithmetic operations defined using opBinary but array operations with arrays of it don't work. struct Vector3 { public double[3] _p; ... Vector3 opBinary(string op)(in Vector3 rhs) const if (op == "+"){ Vector3 result; result._p[] = this._p[] + rhs._p[]; return result; } ... } unittest{ auto a = Vector3([2.0, 2.0, 0.0]); auto b = Vector3([1.0, 2.0, 1.0]); Vector3[] c = [a]; Vector3[] d = [b]; Vector3 e = a + b; // works Vector3[] f; f[] = c[] + d[]; // Error: invalid array operation 'f[] = c[] + d[]' because Vector3 doesn't support necessary arithmetic operations } how can I get this to work? Thanksyou need to define the slice operators. e.g. auto opSlice() // no parameters to get whole slice eg. a[] // can also define with opSlice(size_t i, size_t j) // for access like a[ i .. j] { return _p; }will likely crash because `f` doesn't point to any allocated memory. initialising like Vector3[] f = [Vector3()]; Enhancement Request to tell you the names of the missing methods required filed at https://issues.dlang.org/show_bug.cgi?id=14772auto a = Vector3([2.0, 2.0, 0.0]); auto b = Vector3([1.0, 2.0, 1.0]); Vector3[] c = [a]; Vector3[] d = [b]; Vector3 e = a + b; // works Vector3[] f; f[] = c[] + d[];
Jul 05 2015
On Monday, 6 July 2015 at 03:02:59 UTC, Nicholas Wilson wrote:On Monday, 6 July 2015 at 01:16:54 UTC, Peter wrote:[...]`f`, `c`, and `d` are arrays though, not `Vector3`s. The code doesn't try to slice a Vector3. So as far as I can see, there's no point in adding opSlice to it.unittest{ auto a = Vector3([2.0, 2.0, 0.0]); auto b = Vector3([1.0, 2.0, 1.0]); Vector3[] c = [a]; Vector3[] d = [b]; Vector3 e = a + b; // works Vector3[] f; f[] = c[] + d[]; // Error: invalid array operation 'f[] = c[] + d[]' because Vector3 doesn't support necessary arithmetic operations } how can I get this to work? Thanksyou need to define the slice operators. e.g. auto opSlice() // no parameters to get whole slice eg. a[] // can also define with opSlice(size_t i, size_t j) // for access like a[ i .. j] { return _p; }
Jul 06 2015
On Monday, 6 July 2015 at 01:16:54 UTC, Peter wrote:Hi, I have a struct with arithmetic operations defined using opBinary but array operations with arrays of it don't work. struct Vector3 { public double[3] _p; ... Vector3 opBinary(string op)(in Vector3 rhs) const if (op == "+"){ Vector3 result; result._p[] = this._p[] + rhs._p[]; return result; } ... } unittest{ auto a = Vector3([2.0, 2.0, 0.0]); auto b = Vector3([1.0, 2.0, 1.0]); Vector3[] c = [a]; Vector3[] d = [b]; Vector3 e = a + b; // works Vector3[] f; f[] = c[] + d[]; // Error: invalid array operation 'f[] = c[] + d[]' because Vector3 doesn't support necessary arithmetic operations } how can I get this to work? ThanksWorks for me with various versions of dmd on linux. What compiler are you using, what version of it, what operating system, etc?
Jul 06 2015
On Monday, 6 July 2015 at 10:29:35 UTC, anonymous wrote:Works for me with various versions of dmd on linux. What compiler are you using, what version of it, what operating system, etc?dmd 2.066.1, windows 7 64bit
Jul 06 2015
On Monday, 6 July 2015 at 12:15:22 UTC, Peter wrote:dmd 2.066.1, windows 7 64bitTested it on Windows 7, using dmd 2.066.1: works for me. The exact code I tested (just commented those "..." out): ---- struct Vector3 { public double[3] _p; //... Vector3 opBinary(string op)(in Vector3 rhs) const if (op == "+"){ Vector3 result; result._p[] = this._p[] + rhs._p[]; return result; } //... } unittest{ auto a = Vector3([2.0, 2.0, 0.0]); auto b = Vector3([1.0, 2.0, 1.0]); Vector3[] c = [a]; Vector3[] d = [b]; Vector3 e = a + b; Vector3[] f; f[] = c[] + d[]; } ---- And the command line: dmd -main -unittest test.d
Jul 06 2015
On Monday, 6 July 2015 at 15:48:28 UTC, anonymous wrote: Ok, I disabled everything in the struct except what I posted and it ran. I then uncommented stuff to isolate the cause. I've added in the bits that cause the error below (plus some constructors just for reference). struct Vector3 { public double[3] _p; nogc this(in double[] p) { switch ( p.length ) { case 0: _p[0] = _p[1] = _p[2] = 0.0; break; case 1: _p[0] = p[0]; _p[1] = _p[2] = 0.0; break; case 2: _p[0] = p[0]; _p[1] = p[1]; _p[2] = 0.0; break; default: _p[0] = p[0]; _p[1] = p[1]; _p[2] = p[2]; break; } } nogc this(in double p0, in double p1=0.0, in double p2=0.0) { _p[0] = p0; _p[1] = p1; _p[2] = p2; } nogc this(in Vector3 other) { _p[] = other._p[]; } //... Vector3 opBinary(string op)(in Vector3 rhs) const if (op == "+"){ Vector3 result; result._p[] = this._p[] + rhs._p[]; return result; } // The bits that cause the error: //... Enabling any one (or more) of the following causes the error this(this) { _p = _p.dup; } nogc ref Vector3 opAssign(ref Vector3 rhs) { _p[] = rhs._p[]; return this; } nogc ref Vector3 opAssign(Vector3 rhs) { _p[] = rhs._p[]; return this; } //... } Any ideas about what's happening?
Jul 07 2015
On Tue, 07 Jul 2015 11:09:52 +0000, Peter wrote:Any ideas about what's happening?yes. there is code in "arrayop.c" that tells: // Built-in array ops should be trusted, pure, nothrow and nogc StorageClass stc = STCtrusted | STCpure | STCnothrow | STCnogc; under the hoods compiler rewrites `f[] = c[]+d[];` to this: _arraySliceSliceAddSliceAssign_S3z007Vector3 extern (C) Vector3[] (Vector3[] p2, const Vector3[] p1, const Vector3[] p0) pure nothrow nogc trusted { foreach (p; 0u .. p2.length) { p2[p] = cast(Vector3)(p0[p] + p1[p]); } return p2; } _arraySliceSliceAddSliceAssign_S3z007Vector3(f, c, d); do you see the gotcha? if you uncomment postblit or assigns, this build function fails to compile, as that operations aren't "pure nothrow nogc trusted", and they will be used for either assign or postblitting. the same will happen if you add anything to your `opBinary` which make it unpure/ system (like `writeln`, for example). i.e. Vector3 opBinary(string op : "+") (in Vector3 rhs) const { import std.stdio; writeln("opBinary"); // (1) Vector3 result; result.vdata[] = this.vdata[] + rhs.vdata[]; return result; } BOOM! adding (1) is enough to get the same error. this is what is going on. i don't know why DMD insists on such restrictions for array operations, though.
Jul 07 2015
On Wednesday, 8 July 2015 at 06:05:54 UTC, ketmar wrote:do you see the gotcha? if you uncomment postblit or assigns, this build function fails to compile, as that operations aren't "pure nothrow nogc trusted", and they will be used for either assign or postblitting.So after looking into it a little bit... It looks like the opAssigns can take all the attributes without throwing errors so that's good. The postblit can only not take nogc due to the array duplication which is understandable. I think the postblit might be redundant anyway since the struct is built on a static array so there is no possibility of two different Vect3s "pointing" to the same data. Can someone confirm or does the postblit do anything else?
Jul 11 2015
On Saturday, 11 July 2015 at 13:31:12 UTC, Peter wrote:The postblit can only not take nogc due to the array duplication which is understandable. I think the postblit might be redundant anyway since the struct is built on a static array so there is no possibility of two different Vect3s "pointing" to the same data. Can someone confirm or does the postblit do anything else?The postblit is pointless, yes. The `.dup` copies from one location to another, only for the assignment to copy everything back to the original location; and then the new array is discarded.
Jul 11 2015
On Saturday, 11 July 2015 at 13:31:12 UTC, Peter wrote:So after looking into it a little bit...So now I'm trying to multiply the array by a double but it's giving incompatible type errors. opBinary, opBinaryRight, and opOpAssign are defined. I have: struct Vector3 { public double[3] _p; nogc this(in double[] p){ switch ( p.length ) { case 0: _p[0] = _p[1] = _p[2] = 0.0; break; case 1: _p[0] = p[0]; _p[1] = _p[2] = 0.0; break; case 2: _p[0] = p[0]; _p[1] = p[1]; _p[2] = 0.0; break; default: _p[0] = p[0]; _p[1] = p[1]; _p[2] = p[2]; break; } } nogc this(in double p0, in double p1=0.0, in double p2=0.0){ _p[0] = p0; _p[1] = p1; _p[2] = p2; } nogc this(in Vector3 other){ _p[] = other._p[]; } Vector3 opBinary(string op)(in Vector3 rhs) const if (op == "+") { Vector3 result; result._p[] = this._p[] + rhs._p[]; return result; } Vector3 opBinary(string op)(in double rhs) const if (op == "*") { Vector3 result; result._p[] = this._p[] * rhs; return result; } Vector3 opBinaryRight(string op)(in double lhs) const if (op == "*") { Vector3 result; result._p[] = this._p[] * lhs; return result; } //... pure nothrow trusted nogc ref Vector3 opAssign(ref Vector3 rhs) { _p[] = rhs._p[]; return this; } pure nothrow trusted nogc ref Vector3 opAssign(Vector3 rhs) { _p[] = rhs._p[]; return this; } nogc ref Vector3 opOpAssign(string op)(in double rhs) if (op == "*") { this._p[] *= rhs; return this; } //... } unittest{ auto a = Vector3([2.0, 2.0, 0.0]); auto b = Vector3([1.0, 2.0, 1.0]); Vector3[] c = [a]; Vector3[] d = [b]; Vector3 e = a + b; //fine Vector3[] f; f[] = c[] + d[]; //fine e = 2*a; //fine e = 3.0*a; //fine f[] = 2*c[]; //Error: incompatible types for ((2) * (c[])): 'int' and 'Vector3[]' f[] = 3.0*c[]; //Error: incompatible types for ((3.00000) * (c[])): 'double' and 'Vector3[]' }
Jul 11 2015