I can't explain why this simple code doesn't compile.
class Foo {
<T extends Foo> T method() {
return this;
}
}
The error is: Type mismatch: cannot convert from Foo to T
.
Why not? T
is defined to be Foo
or its subclass.
UPDATE: I found a succinct piece of advice in the Java Tutorials regarding generic methods.
Generic methods allow type parameters to be used to express dependencies among the types of one or more arguments to a method and/or its return type. If there isn't such a dependency, a generic method should not be used.
My interpretation is that a generic method is only appropriate in two scenarios.
Obviously, the simple code in question has no dependency among its arguments and return type, since there are no arguments. So a generic method is inappropriate.
UPDATE2: Now that I'm aware of it, I notice examples of this anti-pattern in open-source projects.
UPDATE3: I think I've found a requirement for generic methods that doesn't involve multiple parameters or a return type. Multiple inheritance would seem to be an exception to the above rule from Java's Tutorials.
<T extends Foo & Bar> void method(T foobar) {
// Call Foo method.
// Call Bar method.
}
Notably, the Collectors
utility class includes generic methods like toList()
that take no arguments. In this case the generic type only parameterizes the return type, which may be safer than the generic type actually being the return type.
I think you misunderstand how Java generics work:
<T extends Foo> T method() {
This means that the caller of that method can pick whatever subtype of Foo
they want and ask for it. For example, you could write
Foo foo = new Foo();
SubFoo subfoo = foo.<SubFoo>method();
...and expect a SubFoo
back, but your method
implementation couldn't return a SubFoo
, and this would have to fail. (I don't speak Scala, but I presume this means that your Scala implementation is not in fact "equivalent.")
If you want your method to be able to return a subtype of Foo
that the implementation chooses, instead of the caller, then just write
Foo method() {
return this;
}