Jump to page: 1 2
Thread overview
Array operations with array of structs
Jul 06, 2015
Peter
Jul 06, 2015
Nicholas Wilson
Jul 06, 2015
Nicholas Wilson
Jul 06, 2015
anonymous
Jul 06, 2015
anonymous
Jul 06, 2015
Peter
Jul 06, 2015
anonymous
Jul 07, 2015
Peter
Jul 08, 2015
ketmar
Jul 11, 2015
Peter
Jul 11, 2015
anonymous
Jul 11, 2015
Peter
July 06, 2015
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

July 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?
>
> Thanks

you 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;
}


July 06, 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:
>> 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
>
> you 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;
> }

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.

>>     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[];

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=14772
July 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?
>
> Thanks

Works for me with various versions of dmd on linux. What compiler are you using, what version of it, what operating system, etc?
July 06, 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:
[...]
>> 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
>
> you 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;
> }

`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.
July 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
July 06, 2015
On Monday, 6 July 2015 at 12:15:22 UTC, Peter wrote:
> dmd 2.066.1, windows 7 64bit

Tested 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
July 07, 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?
July 08, 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.
July 11, 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?

« First   ‹ Prev
1 2