Codebender
Codebender

Reputation: 14438

PECS does not work on return types with interface

Consider the following example,

class ClsA {}
class ClsB {}

interface IntA {}
interface IntB {}

And I have 2 very similar methods:

static <T extends ClsA> T returnC() { // Here T extends the class
    return null;
}

static <T extends IntA> T returnI() { // Here T extends the interface
    return null;
}

And then the method calls:

ClsA ac = returnC(); // This works fine based on inference.

IntA ai = returnI(); // Similarly this works fine based on inference.

But consider the below 2:

ClsB bc = returnC(); // ERROR as expected.

Eclipse Error:

Bound mismatch: The generic method returnC() of type Testing is not applicable for the arguments (). The inferred type ClsB&ClsA is not a valid substitute for the bounded parameter <T extends ClsA>

But the following code compiles fine:

IntB bi = returnI(); // Works fine

Why is that for interface, the generics bound is not considered in return types?

Upvotes: 3

Views: 211

Answers (1)

Konstantin Yovkov
Konstantin Yovkov

Reputation: 62864

The magic words here are raws and multiple inheritance.

Lets first take a look on your returnC method:

static <T extends ClsA> T returnC() {
    return null;
}

The type T is bounded with ClsA, which means that if you invoke the raw returnC method, then the return type will be simply ClsA.

True, when you have this statement: ClsA ac = returnC(); the compiler succeeds with the compilation, because the raw return type of the method is ClsA, which is compatible with the type of ac.

The the raw return type is also the reason for which the statement ClsB bc = returnC(); does not compile.


Now let's take a look on the returnI method:

static <T extends IntA> T returnI() { // Here T extends the interface
    return null;
}

Here, the type parameter is bound to IntA only.

This, however, doesn't mean that the replacement type for T must implement only IntA - the type can implement IntA and IntB at the same time. Statements like IntB bi = returnI(); are allowed, because a type can implement multiple interfaces, but cannot implement multiple classes.

Consider this class:

class SomethingReallyCool implements IntA, IntB { }

This type is a valid substitute for the type-parameter of returnI() and the proof for that is this statement:

IntB bi = YourClass.<SomethingReallyCool>returnI();

Why? Because it's a class that implements IntA and this is the only thing the compiler cares about.

Upvotes: 1

Related Questions