I'm trying to make an API as user friendly as possible.
Let's have:
class B extends A {}
class A {
A setX(){ ...; return this; }
}
Now this
B b = new B().setX();
is invalid, has to be casted:
B b = (B) new B().setX();
Is there a way using generics in A
to make compiler aware of "this" type and accept the first way - without casting and without passing type parameter at the place where used? (I.e. not new B<B>().setX()
, that's ugly.)
I KNOW why Java needs retyping in this case. Please no answers explaing that setX()
returns A. I know that.
I am asking if generics can solve this.
And for those still wanting to tell me that "this is how static typing works" and "not even generics can help with that", consider this valid Java code:
Map<String, String> map = new HashMap(){{ put( "foo", new RuntimeException() );
String foo = map.get("foo"); // ClassCastException!!
So you can see that generics DO allow you get a CCE without actual type cast appearing in the code.
That's the reason why I expect generics to allow getting rid of the explicit type cast.
Also, IIRC C++ allows that.
I copy part of the answer to another question here, explaining the desire for the so called "self type" and the workaround in Java.
Method Chaining
Instead of writing
foo.doA();
foo.doB();
a lot of people would rather want to write
foo.doA().doB();
Unfortunately the language doesn't directly support method chaining even though it is becoming an increasingly desired feature. The workaround is for doA()
to return foo
. It is a little dirty but acceptable.
However if foo
is in a type hierarchy the workaround is broken
class Bar
Bar doA()
class Foo extends Bar
Foo doB();
foo.doA().doB(); // doesn't compile, since doA() returns Bar
So some people call for a special "self type" to solve this problem. Let's say there's a keyword This
to represent "self type"
class Bar
This doA()
foo.doA().doB(); // works, doA() returns the type of foo, which is Foo
It appears that method chaining is the only use case for "self type", so the language probably will never introduce it (it's better to just support method chaining directly)
People found out that generics provides a workaround for this problem
class Bar<This>
This doA()
class Foo extends Bar<Foo>
Foo has a method "Foo doA()", inherited from Bar<Foo>
This is the most popular use case for the A extends B<A>
pattern. It is an isolated workaround/trick. It adds no semantics in relationship between A and B.
It is also a popular practice to constraint This
like
class Bar<This extends Bar<This>>
It is ugly and useless, I strongly recommend against it. Simply use "This" as a convention to indicate what it is for.
Try this in class A:
public <T extends A> T setX() {
return (T) this;
}
And you can use it like this
B b = new B().setX();
If you really don't like the cast you can let B
override the method
@Override
public B setX() {
super.setX();
return this;
}
The problem is that the method setX()
returns object of class A
and you are trying to write it to an object of class B
. It can be done vice-versa without casting (A a = new B();
), but this way you have to cast it because the statement B b = new B().setX();
is similar to B b = new A();
which can't be done.