I playing around with generics and have the following four Java Objects (2 interfaces + 1 abstract class + 1 enum), and an obscure error message. I hope anyone here can explain the reason or maybe even agree with me that it could be a bug:
interface Scalar<T> {
public abstract T getValue();
public abstract void setValue(T value) throws UnsupportedOperationException, NullPointerException;
}
interface Vector<T> {
T getElement(int index) throws IndexOutOfBoundsException;
void setElement(int index, T value) throws UnsupportedOperationException, IndexOutOfBoundsException, NullPointerException;
}
abstract class Vector2<T> implements Vector<T> {
public static enum Elements {
X {
<T> Scalar<T> get(final Vector2<T> source) {
return new Scalar<T>() {
public T getValue() { return source.getElement(0); }
public void setValue(T value) { source.setElement(0, value); }
};
}
},
Y {
<T> Scalar<T> get(final Vector2<T> source) {
return new Scalar<T>() {
public T getValue() { return source.getElement(1); }
public void setValue(T value) { source.setElement(1, value); }
};
}
};
abstract <T> Scalar<T> get(final Vector2<T> source);
}
}
Now, l added a single method to the Vector2 class:
// Compiler Error:
//incompatible types
//found : Scalar<T>
//required: Scalar<T>
// lines
//this.x = x.get(Vector2.this);
//this.y = y.get(Vector2.this);
public Vector2<T> get(Elements x, Elements y) {
final class Swizzle<T> extends Vector2<T> {
private final Scalar<T> x, y;
Swizzle(final Vector2.Elements x, final Vector2.Elements y) {
this.x = x.get(Vector2.this);
this.y = y.get(Vector2.this);
}
public T getElement(int index) { return this.x.getValue(); }
public void setElement(int index, T x) { this.x.setValue(x); }
}
return new Swizzle<T>(x, y);
}
Note, that I am somehow scared by the error message part: found: Scalar, required: Scalar
Then, I thought a local class is like a non-static inner class and therefore implicitly derives the generic type T, but the following also doesn’t work too:
// Compiler Warning/Error with Xlint:unchecked:
// warning: [unchecked] unchecked conversion
// found : Swizzle
// required: Vector2<T>
// lines:
// return new Swizzle(x, y);
public Vector2<T> get(Elements x, Elements y) {
final class Swizzle extends Vector2<T> {
private final Scalar<T> x, y;
Swizzle(final Vector2.Elements x, final Vector2.Elements y) {
this.x = x.get(Vector2.this);
this.y = y.get(Vector2.this);
}
public T getElement(int index) { return this.x.getValue(); }
public void setElement(int index, T x) { this.x.setValue(x); }
}
return new Swizzle(x, y);
}
Again, I was confused that required: Vector but found is Swizzle. Note that Swizzle derives from Vector2 and therefore should be compatible!
Finally, I used an inner class and it worked fine, but I’d preferred a local class:
// Works but I'd prefer a local class instead of an inner class:
final class Swizzle2 extends Vector2<T> {
private final Scalar<T> x, y;
Swizzle2(final Vector2.Elements x, final Vector2.Elements y) {
this.x = x.get(Vector2.this);
this.y = y.get(Vector2.this);
}
public T getElement(int index) { return this.x.getValue(); }
public void setElement(int index, T x) { this.x.setValue(x); }
}
public Vector2<T> get(Elements x, Elements y) {
return new Swizzle2(x, y);
}
Thanks for comments,
Michael