Generic parameter: only diamond operator seems to work

  • A+
Category:Languages

Background: the question came up in this answer (the first revision of the answer, to be exact). The code presented in this question is reduced to the bare minimum to explain the problem.

Suppose we have the following code:

public class Sample<T extends Sample<T>> {      public static Sample<? extends Sample<?>> get() {         return new Sample<>();     }      public static void main(String... args) {         Sample<? extends Sample<?>> sample = Sample.get();     } } 

It compiles without warning and executes fine. However, if one tries to somehow define the inferred type of return new Sample<>(); in get() explicitly the compiler complains.

Up until now, I was under the impression that the diamond operator is just some syntactic sugar to not write explicit tyes and thus could be replaced with some explicit type. For the given example, I was not able to define any explicit type for the return value to make the code compile. Is it possible to explicitly define the generic type of the return value or is the diamond-operator needed in this case?

If this is a duplicate, please let me know and I will gladly delete the question.

Below are some attempts I made to explicitly define the generic type of the returned value with the corresponding compiler errors.


return new Sample<Sample> results in:

Sample.java:6: error: type argument Sample is not within bounds of type-variable T             return new Sample<Sample>();                               ^   where T is a type-variable:     T extends Sample<T> declared in class Sample Sample.java:6: error: incompatible types: Sample<Sample> cannot be converted to Sample<? extends Sample<?>>             return new Sample<Sample>();                    ^ 

return new Sample<Sample<?>> results in:

Sample.java:6: error: type argument Sample<?> is not within bounds of type-variable T             return new Sample<Sample<?>>();                                     ^   where T is a type-variable:     T extends Sample<T> declared in class Sample 

return new Sample<Sample<>>(); results in:

Sample.java:6: error: illegal start of type            return new Sample<Sample<>>();                                     ^ 

 


The JLS simply says:

If the type argument list to the class is empty — the diamond form <> — the type arguments of the class are inferred.

So, is there some inferred X that will satisfy the solution? Yes.

Of course, for you to explicitly define such an X, you'd have to declare it:

public static <X extends Sample<X>> Sample<? extends Sample<?>> get() {     return new Sample<X>(); } 

The explicit Sample<X> is compatible with the return type Sample<? extends Sample<?>>, so compiler is happy.

The fact that return type is a messed up Sample<? extends Sample<?>> is an entirely different story.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: