www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - opBinary failes with templates

reply Asger Dam Hoedt <asgerhoedt gmail.com> writes:
Hey

I've very recently started playing around with D, but I seem to have hit my
head against a bug in dmd. I want to create a Vector class templated with
its dimension. This works fine until I try to overload the + operator for my
vector and use it. I then get the error

Error: incompatible types for ((vec) + (vec)): 'Vector!(3)' and 'Vector!(3)'

I've boiled it down to a small example

struct Vector(int D) {
    float es[D];

public:
    this(immutable float x, immutable float y, immutable float z) {
        es[0] = x; es[1] = y; es[2] = z;
    }

    Vector!(D) opBinary(string s)(immutable Vector!(D) rhs) if (s == "+") {
        Vector!(D) ret;
        for(int i = 0; i < D; ++i)
            ret.es[i] = es[i] + rhs.es[i];
        return ret;
    }

}

alias Vector!(3) Vector3;

void main() {
    Vector3 vec = Vector3(0,1,2);
    vec = vec.opBinary!("+")(vec); // This works fine
    vec = vec + vec; // This line fails miserably
}

If I replace the template argument in for the argument rhs with 3, then
everything works, but that's not really a nice solution :)

Is it me trying to use templates in a way they aren't meant to be used or is
this a bug in dmd? If it is a bug, does anyone have an idea how to solve
this? I wouldn't mind fixing it in dmd myself, I just need some guidelines.

/papaboo

-- 
I confess
---
From the desk of Dr. John Zoidberg, M.D.
(\/)(',,,')(\/)
Jul 27 2011
parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 27 Jul 2011 15:48:24 -0400, Asger Dam Hoedt <asgerhoedt gmail.com>  
wrote:

 Hey

 I've very recently started playing around with D, but I seem to have hit  
 my
 head against a bug in dmd. I want to create a Vector class templated with
 its dimension. This works fine until I try to overload the + operator  
 for my
 vector and use it. I then get the error

 Error: incompatible types for ((vec) + (vec)): 'Vector!(3)' and  
 'Vector!(3)'

 I've boiled it down to a small example

 struct Vector(int D) {
     float es[D];

 public:
     this(immutable float x, immutable float y, immutable float z) {
         es[0] = x; es[1] = y; es[2] = z;
     }

     Vector!(D) opBinary(string s)(immutable Vector!(D) rhs) if (s ==  
 "+") {
         Vector!(D) ret;
         for(int i = 0; i < D; ++i)
             ret.es[i] = es[i] + rhs.es[i];
         return ret;
     }

 }

 alias Vector!(3) Vector3;

 void main() {
     Vector3 vec = Vector3(0,1,2);
     vec = vec.opBinary!("+")(vec); // This works fine
     vec = vec + vec; // This line fails miserably
 }

 If I replace the template argument in for the argument rhs with 3, then
 everything works, but that's not really a nice solution :)

 Is it me trying to use templates in a way they aren't meant to be used  
 or is
 this a bug in dmd? If it is a bug, does anyone have an idea how to solve
 this? I wouldn't mind fixing it in dmd myself, I just need some  
 guidelines.
It is a bug, someone just brought up almost exactly this problem in d.learn. http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.learn&article_id=28455 The proper workaround (and actually, the cleaner solution) is to use Vector and not Vector!D. Inside a template, the name of the template is the same as if you invoked the template with the same template parameters. If you actually do need a different value for D, I'm not sure what works. -Steve
Jul 27 2011
next sibling parent reply Asger Dam Hoedt <asgerhoedt gmail.com> writes:
2011/7/27 Steven Schveighoffer <schveiguy yahoo.com>

 On Wed, 27 Jul 2011 15:48:24 -0400, Asger Dam Hoedt <asgerhoedt gmail.com>
 wrote:

  Hey
 I've very recently started playing around with D, but I seem to have hit
 my
 head against a bug in dmd. I want to create a Vector class templated with
 its dimension. This works fine until I try to overload the + operator for
 my
 vector and use it. I then get the error

 Error: incompatible types for ((vec) + (vec)): 'Vector!(3)' and
 'Vector!(3)'

 I've boiled it down to a small example

 struct Vector(int D) {
    float es[D];

 public:
    this(immutable float x, immutable float y, immutable float z) {
        es[0] = x; es[1] = y; es[2] = z;
    }

    Vector!(D) opBinary(string s)(immutable Vector!(D) rhs) if (s == "+") {
        Vector!(D) ret;
        for(int i = 0; i < D; ++i)
            ret.es[i] = es[i] + rhs.es[i];
        return ret;
    }

 }

 alias Vector!(3) Vector3;

 void main() {
    Vector3 vec = Vector3(0,1,2);
    vec = vec.opBinary!("+")(vec); // This works fine
    vec = vec + vec; // This line fails miserably
 }

 If I replace the template argument in for the argument rhs with 3, then
 everything works, but that's not really a nice solution :)

 Is it me trying to use templates in a way they aren't meant to be used or
 is
 this a bug in dmd? If it is a bug, does anyone have an idea how to solve
 this? I wouldn't mind fixing it in dmd myself, I just need some
 guidelines.
It is a bug, someone just brought up almost exactly this problem in d.learn. http://www.digitalmars.com/**webnews/newsgroups.php?art_** group=digitalmars.D.learn&**article_id=28455<http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.learn&article_id=28455> The proper workaround (and actually, the cleaner solution) is to use Vector and not Vector!D. Inside a template, the name of the template is the same as if you invoked the template with the same template parameters. If you actually do need a different value for D, I'm not sure what works. -Steve
Oh nice. I'll go with the clean solution then and disregard the bug for now. Thanks for the quick help. /asger
Jul 27 2011
parent reply KennyTM~ <kennytm gmail.com> writes:
On Jul 28, 11 05:25, Asger Dam Hoedt wrote:
 2011/7/27 Steven Schveighoffer <schveiguy yahoo.com
 <mailto:schveiguy yahoo.com>>

     On Wed, 27 Jul 2011 15:48:24 -0400, Asger Dam Hoedt
     <asgerhoedt gmail.com <mailto:asgerhoedt gmail.com>> wrote:

         Hey

         I've very recently started playing around with D, but I seem to
         have hit my
         head against a bug in dmd. I want to create a Vector class
         templated with
         its dimension. This works fine until I try to overload the +
         operator for my
         vector and use it. I then get the error

         Error: incompatible types for ((vec) + (vec)): 'Vector!(3)' and
         'Vector!(3)'

         I've boiled it down to a small example

         struct Vector(int D) {
             float es[D];

         public:
             this(immutable float x, immutable float y, immutable float z) {
                 es[0] = x; es[1] = y; es[2] = z;
             }

             Vector!(D) opBinary(string s)(immutable Vector!(D) rhs) if
         (s == "+") {
                 Vector!(D) ret;
                 for(int i = 0; i < D; ++i)
         ret.es <http://ret.es>[i] = es[i] + rhs.es <http://rhs.es>[i];
                 return ret;
             }

         }

         alias Vector!(3) Vector3;

         void main() {
             Vector3 vec = Vector3(0,1,2);
             vec = vec.opBinary!("+")(vec); // This works fine
             vec = vec + vec; // This line fails miserably
         }

         If I replace the template argument in for the argument rhs with
         3, then
         everything works, but that's not really a nice solution :)

         Is it me trying to use templates in a way they aren't meant to
         be used or is
         this a bug in dmd? If it is a bug, does anyone have an idea how
         to solve
         this? I wouldn't mind fixing it in dmd myself, I just need some
         guidelines.


     It is a bug, someone just brought up almost exactly this problem in
     d.learn.

     http://www.digitalmars.com/__webnews/newsgroups.php?art___group=digitalmars.D.learn&__article_id=28455
     <http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.learn&article_id=28455>

     The proper workaround (and actually, the cleaner solution) is to use
     Vector and not Vector!D.  Inside a template, the name of the
     template is the same as if you invoked the template with the same
     template parameters.

     If you actually do need a different value for D, I'm not sure what
     works.

     -Steve


 Oh nice. I'll go with the clean solution then and disregard the bug for
 now. Thanks for the quick help.

 /asger
Actually you shouldn't need to write a vector struct if "+" is all it required, as D supports array operation already: void main() { float[3] x = [1, 3, 5], y = [5, -6, 2]; x[] = x[] + y[]; assert(x == [6, -3, 7]); } It is also more efficient than the for-loop since this could use SIMD operations in some cases.
Jul 27 2011
next sibling parent simendsjo <simendsjo gmail.com> writes:
On 27.07.2011 23:39, KennyTM~ wrote:
 On Jul 28, 11 05:25, Asger Dam Hoedt wrote:
 2011/7/27 Steven Schveighoffer <schveiguy yahoo.com
 <mailto:schveiguy yahoo.com>>

 On Wed, 27 Jul 2011 15:48:24 -0400, Asger Dam Hoedt
 <asgerhoedt gmail.com <mailto:asgerhoedt gmail.com>> wrote:

 Hey

 I've very recently started playing around with D, but I seem to
 have hit my
 head against a bug in dmd. I want to create a Vector class
 templated with
 its dimension. This works fine until I try to overload the +
 operator for my
 vector and use it. I then get the error

 Error: incompatible types for ((vec) + (vec)): 'Vector!(3)' and
 'Vector!(3)'

 I've boiled it down to a small example

 struct Vector(int D) {
 float es[D];

 public:
 this(immutable float x, immutable float y, immutable float z) {
 es[0] = x; es[1] = y; es[2] = z;
 }

 Vector!(D) opBinary(string s)(immutable Vector!(D) rhs) if
 (s == "+") {
 Vector!(D) ret;
 for(int i = 0; i < D; ++i)
 ret.es <http://ret.es>[i] = es[i] + rhs.es <http://rhs.es>[i];
 return ret;
 }

 }

 alias Vector!(3) Vector3;

 void main() {
 Vector3 vec = Vector3(0,1,2);
 vec = vec.opBinary!("+")(vec); // This works fine
 vec = vec + vec; // This line fails miserably
 }

 If I replace the template argument in for the argument rhs with
 3, then
 everything works, but that's not really a nice solution :)

 Is it me trying to use templates in a way they aren't meant to
 be used or is
 this a bug in dmd? If it is a bug, does anyone have an idea how
 to solve
 this? I wouldn't mind fixing it in dmd myself, I just need some
 guidelines.


 It is a bug, someone just brought up almost exactly this problem in
 d.learn.

 http://www.digitalmars.com/__webnews/newsgroups.php?art___group=digitalmars.D.learn&__article_id=28455

 <http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.learn&article_id=28455>


 The proper workaround (and actually, the cleaner solution) is to use
 Vector and not Vector!D. Inside a template, the name of the
 template is the same as if you invoked the template with the same
 template parameters.

 If you actually do need a different value for D, I'm not sure what
 works.

 -Steve


 Oh nice. I'll go with the clean solution then and disregard the bug for
 now. Thanks for the quick help.

 /asger
Actually you shouldn't need to write a vector struct if "+" is all it required, as D supports array operation already: void main() { float[3] x = [1, 3, 5], y = [5, -6, 2]; x[] = x[] + y[]; assert(x == [6, -3, 7]); } It is also more efficient than the for-loop since this could use SIMD operations in some cases.
The last time I tried to use vector ops, they failed for all but the most straight forward use-cases. I was told it wasn't fully implemented yet. Is this still the case, or are they ready for prime-time?
Jul 27 2011
prev sibling parent Peter Alexander <peter.alexander.au gmail.com> writes:
On 27/07/11 10:39 PM, KennyTM~ wrote:
 Actually you shouldn't need to write a vector struct if "+" is all it
 required, as D supports array operation already:



 void main() {
 float[3] x = [1, 3, 5], y = [5, -6, 2];
 x[] = x[] + y[];
 assert(x == [6, -3, 7]);
 }


 It is also more efficient than the for-loop since this could use SIMD
 operations in some cases.
For 3 floats, it will not be more efficient. In my experiments, manually writing: x[0] += y[0]; x[1] += y[1]; x[2] += y[2]; Is about 6x faster than calling x[] = x[] + y[]; // or x[] += y[]; same result You only get the advantage of the SIMD arrays ops in large arrays. The overhead of the function call, loading the scalars into and out of vector registers, and looping through the array is way more than the work that needs to be done. DMD really shouldn't call those SIMD array ops for small statically sized arrays.
Jul 28 2011
prev sibling parent Pelle <pelle.mansson gmail.com> writes:
On Wed, 27 Jul 2011 22:46:21 +0200, Steven Schveighoffer  
<schveiguy yahoo.com> wrote:
 The proper workaround (and actually, the cleaner solution) is to use  
 Vector and not Vector!D.  Inside a template, the name of the template is  
 the same as if you invoked the template with the same template  
 parameters.

 If you actually do need a different value for D, I'm not sure what works.

 -Steve
It does not, for example: struct matrix(uint m, uint n) { //... matrix!(n,m) transposed() { //... } } matrix(3,1) m; m = m.transposed().transposed(); // doesn't work
Jul 28 2011