Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

return this from a generic method generalized with <T extends TestClass>

Why can't I do this in Java:

public class TestClass {

    public <T extends TestClass> T test(){
        return this; // error here
    }
}

As I understand, this will always be an instance of some class that extends TestClass, so why the code above is not allowed by compiler? Even if I will extend the TestClass then type of this will fit extends TestClass anyway. I get the following error:

Error:(4, 16) java: incompatible types: TestClass cannot be converted to T

like image 638
peremeykin Avatar asked Dec 08 '18 14:12

peremeykin


1 Answers

Say you have SubTestClass extends TestClass, and you write:

TestClass instance = new TestClass();
SubTestClass result = instance.test();

This is legal regarding the signature of your test() class, although nonsense (1). The compiler will deduce that T is the class SubTestClass. And then it's clear that a TestClass instance isn't instanceof SubTestClass. So with legal usage of your test() method, returning this can produce type mismatches, and that's what the compiler tells you.

With your test() signature, it's impossible to return anything other than null, because null is the only value you can assign to a variable of unknown type.

Let me explain that last claim (asked for in comments): The implementation of the test() method has to return some value that matches the T type, and the concrete type (deduced from the call situation to be SubTestClass) isn't deducible to the method - there's nothing in the arguments or in the instance fields where it can read out the requirement to return a SubTestClass in this situation. In another call situation, it might be required to return AnotherSubTestClass, and there's no way it can tell the first from the second situation.

If you return this (with (T) casting to make it pass the compiler), it will fail either in the first or in the second or in both situations. So you can't do that without high risk of failure.

The only value that you can successfully assign to both a SubTestClass and a AnotherSubTestClass variables, is the null value. So that's the only value you can safely return from a method with such a signature.

(1) Having a generic method where the generic type can't be deduced from the parameters, but instead only from the expected result type, can hardly work - how should the method know what the caller expects?

like image 151
Ralf Kleberhoff Avatar answered Oct 26 '22 01:10

Ralf Kleberhoff