www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - opBinary failes with templates

reply Asger Dam Hoedt <asgerhoedt gmail.com> writes:
--0016e645fabedda52c04a9125492
Content-Type: text/plain; charset=UTF-8

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.

--0016e645fabedda52c04a9125492 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Hey<div><br></div><div>I&#39;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 V= ector class templated with its dimension. This works fine until I try to ov= erload the + operator for my vector and use it. I then get the error=C2=A0<= /div> <div><br></div><div>Error: incompatible types for ((vec) + (vec)): &#39;Vec= tor!(3)&#39; and &#39;Vector!(3)&#39;</div><div><br></div><div>I&#39;ve boi= led it down to a small example</div><div><br></div><div><div>struct Vector(= int D) {</div> <div>=C2=A0 =C2=A0 float es[D];</div><div>=C2=A0 =C2=A0=C2=A0</div><div>pub= lic:</div><div>=C2=A0 =C2=A0 this(immutable float x, immutable float y, imm= utable float z) {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 es[0] =3D x; es[1] = =3D y; es[2] =3D z;</div><div>=C2=A0 =C2=A0 }</div><div>=C2=A0 =C2=A0=C2=A0= </div><div> =C2=A0 =C2=A0 Vector!(D) opBinary(string s)(immutable Vector!(D) rhs) if (s= =3D=3D &quot;+&quot;) {=C2=A0</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 Vector= !(D) ret;</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 for(int i =3D 0; i &lt; D; = ++i)</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 <a href=3D"http://= ret.es">ret.es</a>[i] =3D es[i] + <a href=3D"http://rhs.es">rhs.es</a>[i];<= /div> <div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 return ret;=C2=A0</div><div>=C2=A0 =C2=A0 = }</div><div>=C2=A0 =C2=A0=C2=A0</div><div>}</div><div><br></div><div>alias = Vector!(3) Vector3;</div><div><br></div><div>void main() {</div><div>=C2=A0= =C2=A0 Vector3 vec =3D Vector3(0,1,2);</div><div>=C2=A0 =C2=A0 vec =3D vec= .opBinary!(&quot;+&quot;)(vec); // This works fine</div> <div>=C2=A0 =C2=A0 vec =3D vec + vec; // This line fails miserably</div><di= v>}</div></div><div><br></div><div>If I replace the template argument in fo= r the argument rhs with 3, then everything works, but that&#39;s not really= a nice solution :)</div> <div><br></div><div>Is it me trying to use templates in a way they aren&#39= ;t meant to be used or is this a bug in dmd? If it is a bug, does anyone ha= ve an idea how to solve this? I wouldn&#39;t mind fixing it in dmd myself, = I just need some guidelines.</div> <div><br></div><div>/papaboo</div><div><br>-- <br>I confess<br>---<br>From = the desk of Dr. John Zoidberg, M.D.=C2=A0<div>(\/)(&#39;,,,&#39;)(\/)</div>= <br> </div> --0016e645fabedda52c04a9125492--
Jul 27 2011
next sibling 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
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 next sibling parent Asger Dam Hoedt <asgerhoedt gmail.com> writes:
--0022152d5ed5869d4104a913b08f
Content-Type: text/plain; charset=UTF-8

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 --0022152d5ed5869d4104a913b08f Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div class=3D"gmail_quote">2011/7/27 Steven Schveighoffer <span dir=3D"ltr"=
&lt;<a href=3D"mailto:schveiguy yahoo.com">schveiguy yahoo.com</a>&gt;</sp=

left:1px #ccc solid;padding-left:1ex;"> <div><div></div><div class=3D"h5">On Wed, 27 Jul 2011 15:48:24 -0400, Asger= Dam Hoedt &lt;<a href=3D"mailto:asgerhoedt gmail.com" target=3D"_blank">as= gerhoedt gmail.com</a>&gt; wrote:<br> <br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> Hey<br> <br> I&#39;ve very recently started playing around with D, but I seem to have hi= t my<br> head against a bug in dmd. I want to create a Vector class templated with<b= r> its dimension. This works fine until I try to overload the + operator for m= y<br> vector and use it. I then get the error<br> <br> Error: incompatible types for ((vec) + (vec)): &#39;Vector!(3)&#39; and &#3= 9;Vector!(3)&#39;<br> <br> I&#39;ve boiled it down to a small example<br> <br> struct Vector(int D) {<br> =C2=A0 =C2=A0float es[D];<br> <br> public:<br> =C2=A0 =C2=A0this(immutable float x, immutable float y, immutable float z)= {<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0es[0] =3D x; es[1] =3D y; es[2] =3D z;<br> =C2=A0 =C2=A0}<br> <br> =C2=A0 =C2=A0Vector!(D) opBinary(string s)(immutable Vector!(D) rhs) if (s= =3D=3D &quot;+&quot;) {<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0Vector!(D) ret;<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0for(int i =3D 0; i &lt; D; ++i)<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0<a href=3D"http://ret.es" target= =3D"_blank">ret.es</a>[i] =3D es[i] + <a href=3D"http://rhs.es" target=3D"_= blank">rhs.es</a>[i];<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0return ret;<br> =C2=A0 =C2=A0}<br> <br> }<br> <br> alias Vector!(3) Vector3;<br> <br> void main() {<br> =C2=A0 =C2=A0Vector3 vec =3D Vector3(0,1,2);<br> =C2=A0 =C2=A0vec =3D vec.opBinary!(&quot;+&quot;)(vec); // This works fine= <br> =C2=A0 =C2=A0vec =3D vec + vec; // This line fails miserably<br> }<br> <br> If I replace the template argument in for the argument rhs with 3, then<br> everything works, but that&#39;s not really a nice solution :)<br> <br> Is it me trying to use templates in a way they aren&#39;t meant to be used = or is<br> this a bug in dmd? If it is a bug, does anyone have an idea how to solve<br=

nes.<br> </blockquote> <br></div></div> It is a bug, someone just brought up almost exactly this problem in d.learn= .<br> <br> <a href=3D"http://www.digitalmars.com/webnews/newsgroups.php?art_group=3Ddi= gitalmars.D.learn&amp;article_id=3D28455" target=3D"_blank">http://www.digi= talmars.com/<u></u>webnews/newsgroups.php?art_<u></u>group=3Ddigitalmars.D.= learn&amp;<u></u>article_id=3D28455</a><br> <br> The proper workaround (and actually, the cleaner solution) is to use Vector= and not Vector!D. =C2=A0Inside a template, the name of the template is the= same as if you invoked the template with the same template parameters.<br> <br> If you actually do need a different value for D, I&#39;m not sure what work= s.<br> <br> -Steve<br> </blockquote></div><br>Oh nice. I&#39;ll go with the clean solution then an= d disregard the bug for now. Thanks for the quick help. <div><br></div><div>/asger</div> --0022152d5ed5869d4104a913b08f--
Jul 27 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