Reputation: 9553
I wan't to be able to method chain multiple vector class that build on top of each other. I want to be able to extend that class.
Here is the 2d one:
public class Vec2 < C extends Vec2 > {
public double x, y;
public Vec2() {
}
public Vec2(double x, double y) {
this.x = x;
this.y = y;
}
public C add(double x, double y) {
this.x += x;
this.y += y;
return (C) this;
}
}
This is for a vector with a z element.
class Vec3 < C extends Vec3 > extends Vec2<Vec3> {
double z;
public Vec3(){}
public Vec3(double x, double y, double z) {
super(x, y);
this.z = z;
}
public C add(double x, double y, double z) {
super.add(x, y);
this.z += z;
return (C) this;
}
}
But when is use a Vec3 then as soon as I use a method from Vec2 twice in a row then it returns a Vec2.
Vec3<Vec3> a = new Vec3<>();
// ------------------------------------------------->.add() in Vec2 cannot be aplied
a.add(10, 20).add(10, 20, 10).add(10, 20).add(10, 20).add(10, 10, 20);
I don't want to write the class like this:
class Vec3 extends Vec2<Vec3> {
// constructor etc. like before...
public Vec3 add(double x, double y, double z) {
super.add(x, y);
this.z += z;
return this;
}
}
Cause then when I make a Vec4 for example I have to Override every method in Vec3.
Is there a way (syntax) around this problem? Where no matter what It keeps returning the right class.
Upvotes: 2
Views: 98
Reputation: 425208
You can't implement your code exactly as you intended, but the following compiles and I believe captures your intent:
interface Vec<C extends Vec<C>> {
C add(C c);
}
class Vec2 implements Vec<Vec2> {
public double x, y;
public Vec2() {
}
public Vec2(double x, double y) {
this.x = x;
this.y = y;
}
public Vec2 add(Vec2 c) {
this.x += c.x;
this.y += c.y;
return this;
}
}
static class Vec3 implements Vec<Vec3> {
Vec2 vec2;
double z;
public Vec3() {
this(0,0,0);
}
public Vec3(double x, double y, double z) {
vec2 = new Vec2(x, y);
this.z = z;
}
public Vec3 add(Vec3 c) {
vec2.add(new Vec2(c.vec2.x, c.vec2.y));
this.z += z;
return this;
}
}
Upvotes: 0
Reputation: 19682
The problem is that you had a lot of "raw" type in your definitions, e.g.
Vec2 < C extends Vec2 >
----
raw type!
After a few rounds, you'll reach a raw type, and erasure makes C
the same as Vec2
.
We can do the following, using type variable This
as the "self type"
public class Vec2<This> {
public This add(double x, double y) {
this.x += x;
this.y += y;
return (This) this;
}
}
public class Vec3<This> extends Vec2<This> {
public This add(double x, double y, double z) {
super.add(x, y);
this.z += z;
return (This) this;
}
}
public class Vec4<This> extends Vec3<This> {
etc.
But wait a second, how do we supply a This
to Vec3
?
Vec3<Vec3<Vec3<......>>> ???
We can use a helper class
public class V3 extends Vec3<V3>{}
Now it all works; all add()
methods in V3
return V3
V3 a = new V3();
a.add(10, 20).add(10, 20, 10).add(10, 20).add(10, 20).add(10, 10, 20);
Upvotes: 2