views:

913

answers:

4

we have a function more or less like the following. however we currently return List which in function bla() would return List<Bar> at runtime.

I'm looking for a way to make both

List<Interface> =  toubleFuction(foo, bar.getCLass());;

and

List<Bar> = toubleFuction(foo, bar.getCLass());;

possible. basicaly i want it to return List which would be compatible with interface however this gives the following error

*Type mismatch: cannot convert from List<capture#3-of ? extends Bar> to List<Interface>*

is there any way to make this return type possible or does runtime erasure make this impossible

public <T1 extends Interface, T2 extends Interface> List<"problem"> troubleFunction( T1 in, Class<T2> clazz) {
  return in.doStuffWhichGeneratesAlistOF(clazz)
}

public void bla() {
  Foo foo = new Foo(); // implements interface
  Bar bar = new Bar(); // implements interface
  List<Interface> ifaces = toubleFuction(foo, bar.getCLass());
  List<Bar> mustAlsoWork = toubleFuction(foo, bar.getCLass());
}

edit: in a lot of the existing code base the method is called like

List<Bar> result = troubleFunction(List<Interface> list, Bar.class);

thus this return type must stay compatible (rewrite/re-factor is not an option)

essentially i want the method to return List<? super Bar> if called as

troublefunction(foo, Bar.class);

and List<? super Foo> when called as

troublefunction(foo, Bar.class);
+1  A: 

Generally speaking in situations like this, you need to explicitly pass a Class object in (generically parameterised) which is used for the return value.

However it looks like you've done this already in your case, so would it not work for troubleFunction to be declared to return List<T2>? Alternatively, if you want to keep it general then have it return List<? extends Interface>.

Andrzej Doyle
A: 

As I understand it, the argument types are looked at before the target type to infer the generic arguments. So, I guess you need to explicitly specify the generic arguments, which I think goes something like this:

List<Interface> iface = this.<Interface>troubleFunction(foo, bar.getCLass());

where

public <T extends Interface> List<T> troubleFunction(
    T in, Class<? extends T> clazz
) {
Tom Hawtin - tackline
+1  A: 

You're not giving us enough information to really tell what you need to do. For example, you didn't give us the type signature of doStuffWhichGeneratesAlistOF() or tell us what it does. And you didn't tell us what the type of the "in" argument has to do with all of this.

Sure, it's possible to have the return type of a method be generic. For example,

public <T extends Interface> List<T> troubleFunction(Interface in, Class<? extends T> clazz) {
  List<T> result = new ArrayList<T>();
  result.add(clazz.newInstance());
  return result;
}

And then you could call the method directly like this and it would work (you don't need to specify the type parameter explicitly because it's inferred from the assignment):

List<Interface> iface = this.troubleFunction(foo, bar.getCLass());

But seeing as how in your code above you return the result of in.doStuffWhichGeneratesAlistOF(clazz), you would probably have to make the return type of that method generic also. But I can't really help you on that because we don't have any information on that method.

newacct
the in function returns an list of instances of class Bar when called as foo.doStuffWhichGeneratesAlistOF(Bar.class)
pvgoddijn
A: 

i've looked at this again and the problem was that i wanted to use a 'super' return type the signature i was looking for was more or less:

 public <T1 extends interface, T2 super T1> List<T2> getAList(Class<T1> clazz);

which is not possible

pvgoddijn