## digitalmars.D - opBinary failes with templates

• Asger Dam Hoedt (36/37) Jul 27 2011 Hey
• Steven Schveighoffer (10/47) Jul 27 2011 It is a bug, someone just brought up almost exactly this problem in
• Asger Dam Hoedt (4/63) Jul 27 2011 Oh nice. I'll go with the clean solution then and disregard the bug for ...
• KennyTM~ (10/68) Jul 27 2011 Actually you shouldn't need to write a vector struct if "+" is all it
• simendsjo (4/96) Jul 27 2011 The last time I tried to use vector ops, they failed for all but the
• Peter Alexander (14/23) Jul 28 2011 For 3 floats, it will not be more efficient.
• Pelle (11/17) Jul 28 2011 It does not, for example:
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
"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
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
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
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
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
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