Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Generic type inference derived from method return type

public class TestCase {
    public static String compiles() {
        return getAction();
    }

    /*
    public static String doesntCompile1() {
        return (String) getAction();
    }

    public static String doesntCompile2() {
        return TestCase.<String> getAction();
    }
    */

    public static <T extends javax.swing.Action> T getAction() {
        return (T) null;
    }
}

Should this be considered a bug in javac v1.6.0_22 and jdt v3.7.1? To me it seems that way since in the other cases, the compiler actually finds the potential ClassCastException. In the compiles method, this will throw at ClassCastException at runtime.

The original code that brought this exemple didn't compile in javac, printing the following exception. Unfortunately, the exemple code I provided for some reason will not generate this error.

type parameters of <T>T cannot be determined;
no unique maximal instance exists for type variable T with upper bounds
like image 597
ebelanger Avatar asked Nov 05 '22 07:11

ebelanger


1 Answers

I would expect a good compiler to be able to detect the error, but as an optimization. You present a specific case of a more general case like this:

public class TestCase {
    public static TypeA methodA() {
        return methodB();
    }

    public static <T extends TypeB> T methodB() {
        return (T) null;
    }
}

Now, in general there's nothing wrong with that, provided:

  1. If TypeA and TypeB are both classes then TypeB is a superclass of TypeA.
  2. TypeA or one of TypeA's subtypes inherits from TypeB.

Now the key thing that the compiler isn't checking is #2, when it can in this case. But that is only because String is a final class. If the class isn't final, #2 will always be true because the potential subclasses aren't known at compile time.

Imagine that instead of String, you used CharSequence. Then I would expect all three to compile. However, I cannot explain why in your example the second and third method do not compile.

Edit

And now I have tried it with javac, and have found that the first method does not compile either. The above accepts the premise of your question which seems to be false. I get the misleading compile error

Incompatible types. Required: java.lang.String. Found: T.

This answer doesn't answer the full question, but rather explains why it doesn't work but something like this:

public static CharSequence compiles() {
    return (CharSequence)getAction();
}

does.

like image 188
Mark Peters Avatar answered Nov 09 '22 11:11

Mark Peters