Paul C
Paul C

Reputation: 8497

I have a generic method that will not take the type I parameterized it to

I would like to take the contents of the G.myUglyList list here and pass it to the Outer.send() method. I do not understand why this gives a compiler error. ? extends Inner is the type I parameterize Outer with. So why is it rejecting an Inner passed to it? It wants a "? extends Inner", which isn't a type.

I want the list declared as List<Outer<? extends Inner>> so it can take subtypes of Inner. (Please see the edit below for why this is)

interface Outer<T> {
    void send(T message);
}
interface Inner {}
interface Inner2 extends Inner {}

public class G {

    List<Outer<? extends Inner>> myUglyList;

    void foo() {
        Inner xxx = null;
        for (Outer<? extends Inner> outer : myUglyList) {
            outer.send(xxx); //error
        }
    }
}

I get this error:

error: method send in interface Outer<T#2> cannot be applied to given types;
required: CAP#1
found: Inner<T#1>
reason: actual argument Inner<T#1> cannot be converted to CAP#1 by method invocation conversion
where T#1,T#2 are type-variables:
T#1 extends Object declared in class G
T#2 extends Object declared in interface Outer
where CAP#1 is a fresh type-variable:
CAP#1 extends Inner<T#1> from capture of ? extends Inner<T#1>

edit: I got a lot of answers saying just make the list of type List<Outer<Inner>>, but that is incorrect. I will not be able to add subtypes of Inner if I do that. If I try to add an Outer<Inner2>, it would fail. So list must be of type List<Outer<? extends Inner>>.

interface Inner2 extends Inner {}        
class G {
  void foo() {
    Outer<Inner2> foiled = null;
    myUglyList.add(foiled);   //this will fail if list is of type List<Outer<Inner>>
    Inner xxx = null;
    for (Outer<? extends Inner> outer : myUglyList) {
    outer.send(xxx); //error
  }

Upvotes: 3

Views: 1407

Answers (5)

newacct
newacct

Reputation: 122518

PECS - Producer extends Consumer super

Because outer is parameterized with extends, you cannot pass anything (except null) into its send method.

Upvotes: 1

dinox0r
dinox0r

Reputation: 16059

Change your code for:

interface Outer<T> {
    void send(T message);
}
interface Inner {}
interface Inner2 extends Inner {}

public class G {

    List<Outer<Inner>> myUglyList;

    void foo() {
        Inner2 xxx = null;
        for (Outer<Inner> outer : myUglyList) {
            outer.send(xxx); //error
        }
    }
}

And it will compile

Update:

// No matter if you put 'T extends Inner' here, the 'add' won't compile
interface Outer<T extends Inner> {
    void send(T message);
}
interface Inner {}
interface Inner2 extends Inner {}

public class G {

    List<Outer<Inner>> myUglyList;

    void foo() {
        Outer<Inner2> foiled = null;

        // This way, the 'add' invocation will compile, but it 
        // breaks the generic and generates a warning.
        //
        // Casting 'foiled' to (Outer<Inner>) will also fail
        // because the compiler sees Outer<Inner2> as complete different type
        // from Outer<Inner>
        myUglyList.add((Outer) foiled);  

        Inner xxx = null;
        for (Outer<Inner> outer : myUglyList) {
            outer.send(xxx); //error
        }
    }
}

Upvotes: 3

Bhesh Gurung
Bhesh Gurung

Reputation: 51030

 for (Outer<? extends Inner> outer : myUglyList) {
     outer.send(xxx); //error
 }

In that, Outer<? extends Inner> outer, so the actual type is unknown (?). send takes something unknown that extends Inner, and also outer has something that extends Inner but still unknown.

Update

interface Outer<T extends Inner> {
    void send(T message); //this can take instance of subtype of Inner
}
interface Inner {}
interface Inner2 extends Inner {}

class G {

    List<Outer<Inner>> myUglyList; //you can add instances of subtypes of Inner

    void foo() {
        Inner xxx = null;
        for (Outer<Inner> outer : myUglyList) {
            outer.send(xxx); //error
        }
    }
}

Upvotes: 1

Miserable Variable
Miserable Variable

Reputation: 28761

outer is of type Outer<? extends Inner>, i.e. of some unknown subtype of Inner and its send method takes an object of that same subtype.

For example outer may be of type Outer<OtherInner> and then outer.send needs a OtherInner, so outer.send(xxx) would be wrong.

Upvotes: 2

Ted Hopp
Ted Hopp

Reputation: 234857

Just declare

List<Outer<Inner>> myUglyList;

You can then add subtypes of Inner without restriction. By declaring it

List<Outer<? extends Inner>> myUglyList;

you are saying that myUglyList is "a list of Outer<some specific (but unknown) subtype of Inner>". That's not what you want.

Upvotes: 2

Related Questions