0

I'm having trouble understanding why I can use bounded wildcards like this, if I can't (seem to) make any (genericly-typed) use of it.

If I have a wildcard field in a class, I can't use any of the methods with generic parameters of the implemented interface (unless I supply null as the argument).

class SomeClass {}

class DerivedClass extends SomeClass {}

interface IInterf<T extends SomeClass> {
    T returnsT();
    void paramT(T parm);
    T paramAndReturnT(T parm);
    int nonGenericMethod(int x);
}

class Impl {
    protected IInterf<?> field; //this is bound to <extends SomeClass>
                                //- it's implied by the definition 
                                //  of IInterf which is bound
                                // but what's the point?

    public Impl(IInterf<? extends SomeClass> var){
        field = var;
    }
    public void doSmth(){

        SomeClass sc = field.returnsT();  //works

        field.paramT(new SomeClass());
          //error: method paramT in interface IInterf<T> cannot be applied to given types;
          //required: CAP#1
          //found: SomeClass
          //reason: actual argument SomeClass cannot be converted to CAP#1 by method invocation conversion
          //where T is a type-variable:
          //  T extends SomeClass declared in interface IInterf
          //where CAP#1 is a fresh type-variable:
          //  CAP#1 extends SomeClass from capture of ? 

         field.paramT(null); //works

        SomeClass sc2 = field.paramAndReturnT(new DerivedClass());
          //error: method paramAndReturnT in interface IInterf<T> cannot be applied to given types;
          // SomeClass sc2 = field.paramAndReturnT(new DerivedClass());           //required: CAP#1
          //found: DerivedClass
          //reason: actual argument DerivedClass cannot be converted to CAP#1 by method invocation conversion
          //where T is a type-variable:
          //  T extends SomeClass declared in interface IInterf
          //where CAP#1 is a fresh type-variable:
          //  CAP#1 extends SomeClass from capture of ?            
          //
        int x = field.nonGenericMethod(5);  //obviously works.
    }
}

FWIW, I couldn't convince the C# compiler to accept something similar.

Am I missing something?

Cristian Diaconescu
  • 34,633
  • 32
  • 143
  • 233

3 Answers3

1

When you declare field as

protected IInterf<?> field;

the ? stands for an unknown class that extends SomeClass. Think of it not a s a wildcard but as a particular class deriving SomeClass but anonymous.

If you now try to call

field.paramT(new SomeClass());

this fails because a SomeClass instance is not compatible to what the ? is standing for, namely the anonymous class that extends SomeClass.

There is no problem to use null, this is compatible with any class.

Exactly the same happens with

SomeClass sc2 = field.paramAndReturnT(new DerivedClass());
Henry
  • 42,982
  • 7
  • 68
  • 84
  • Your explanation is not entirely correct: when using `protected IInterf> field;` even `field.paramAndReturnT(new DerivedClass());` will fail to compile even though `DerivedClass` extends `SomeClass`. – praseodym Jan 12 '13 at 16:19
  • 1
    @praseodym Where did I say it would compile? The `?` stands for an unknown class that extends `SomeClass`. This unknown class has nothing to do with `DerivedClass` except that both happen to have `SomeClass` as a superclass. – Henry Jan 12 '13 at 16:29
  • You did not, but I inferred that from the "what the `?` is standing for, namely a class that extends `SomeClass`." since `DerivedClass` does extend `SomeClass` — it's a bit more complicated than that (see my answer). – praseodym Jan 12 '13 at 16:31
  • @praseodym: Henry is correct. His explanation is very clear. The `?` stands for some unknown subtype of `SomeClass`, i.e. it is some subclass and you don't know, and can't know, what it is. i.e. the compiler can replace it with any subclass of `SomeClass` (e.g. `DerivedClass` or even `SomeBogusSubclassIMadeUp`) and it will work. `DerivedClass` cannot be passed because it is not assignable to `SomeBogusSubclassIMadeUp` – newacct Jan 12 '13 at 21:26
0

You are right, you can't use these methods. Often, you don't need these methods (for example, you add something <? extends T> to a collection <T>. It makes sense to use them if you don't need more information. If you need to call these methods, you can't use wildcards. Instead, you could do <T extends SomeClass>.

kutschkem
  • 7,826
  • 3
  • 21
  • 56
0

You're trying to use generics/wildcards where they are not needed. Instead, either of the following will work:

1) Define the interface so that it accepts any class, and limit the types when using the interface:

interface IInterf<T> {}
protected IInterf<SomeClass> field;

2) Define the interface so that it accepts classes that extend SomeClass, and use the interface without specifying extra type information:

interface IInterf<T extends SomeClass> {}
protected IInterf field;

As for why the wildcard does not work: ? extends SomeClass means an unknown subtype of SomeClass. Since we don't know what the type is, we don't know if it is a supertype of SomeClass (or DerivedClass in the second method call); it might or might not be such a supertype, so it isn't safe to pass SomeClass (or DerivedClass). (from the Java Wildcards documentation)

praseodym
  • 2,134
  • 15
  • 29