Nested Generic Types & Lower Bounds
Hi,
As many people appear to be, I am having trouble with nested parameterized types, in this case specifying a lower bound.
In this example I have typed Actions which are typed based on a type on Context (this isn't my exact problem but is the same). There are then handlers which can handle these actions (or a subtype of them). So we have:
class Context{}
class Action<Textends Context>{}
class Handler<Textends Action><?>>{
void handle(T t){};
}
And now for a specific handler:
class SpecialContextextends Context{}
class SpecialHandlerextends Handler<Action><SpecialContext>>{
void handle(Action<SpecialContext> t){}
}
Now I would like to create a list of handlers which can handle an Action<T> - therefore ones which accept any supertype of T (i.e. which I can pass a T to):
List<Handler><?super Action<?super T>>> list =new ArrayList<Handler><?super Action<?super T>>>();
list.add(new SpecialHandler());
Now this doesn't work as I can't add the SpecialHandler. What am I doing wrong here? Have I specified my list incorrectly? I certainly want the two 'super' clauses in there - an 'extends' before the Handler would also be ok but still won't work.
Is what I am trying to do possible?
Thanks
[2352 byte] By [
j_p_ga] at [2007-11-27 1:37:29]

# 1
The last two lines make no sense: what is T? I assume it is SpecialContext since Context itself has no superclass, which would make "? super Context" a non-sequitur. This works:
public static void test() {
Handler<? extends Action<? super SpecialContext>> handler = new SpecialHandler();
List<Handler><? extends Action<? super SpecialContext>>> list = Util.newArrayList();
list.add(new SpecialHandler());
}
Two comments. First, it makes no sense anyhow to write "? super Action" since Action extends Object directly and thus has no "useful" superclasses. Second, I found it useful to break the down problem, starting from the innermost layer and working outwards, hence the assignment to Handler: that showed that the problem was not with the typing of the list but with that of the handler itself.
# 2
Sorry; T in this case is a type parameter for the class containing the snippet:
class HandlerFactory<T extends Context> { ... }
It is a T though, not a SpecialContext because SpecialContext is just one particular subclass of Context, there are others so I can't use this directly.
Also the returned list cannot be of type Handler<? extends Action<...>> because this could contain handlers which only handle subclasses of Action - and I only know I have an Action. (And you're right that there's no superclass of Action, so I don't really need the <? super Action>, I just wanted it in case I added a superclass).
Does this make sense?
Thanks
# 3
Sorry but it still doesn't make sense because we still have to know what T is. Your HandlerFactory class probably looks like this
public class HandlerFactory<T extends Context> {
public List<Handler><? extends Action<? super T>>> createList() {
return new ArrayList<Handler><? extends Action<? super T>>>();
}
}
but in order to get one of those handler lists you need to instantiate a HandlerFactory object of a specific type and hence you have to decide which T to use. For instance this works:
new HandlerFactory<SpecialContext>().createList().add(new SpecialHandler());
> Also the returned list cannot be of type Handler<? extends Action<...>> because this
> could contain handlers which only handle subclasses of Action
No. This would cover plain Actions, too. E.g., this works, too:
new HandlerFactory<SpecialContext>().createList().add(new Handler<Action><Context>>());
Also, generally speaking, adding superclasses in a hierarchy requires changing the formerly top class that is being "demoted", which requires source access. Library users by definition don't have it and shouldn't be performing surgery on the library even if they did have it anyhow (that is not their position) so the point is moot. OTOH you have source access but if you later decide to add a superclass to Action you can always make the necessary adjustments to your generic declarations then; to try to make allowances for this possibility now needlessly complicates what is already a frustrating enough business.
# 4
You say that this would cover plain Actions too - this is fine, it's subclasses that I believe would cause problems - couldn't you also add an ExtraspecialHandler which extends Handler<ExtraspecialContext>. This would not work for me as the ExtraspecialHandler would require ExtraspecialContext and I only have a SpecialContext (this is why I suggested the <? super Action<? super T>>)? i.e:
new HandlerFactory<SpecialContext>().createList().add(new ExtraspecialHandler());
Also I am trying to create concrete subclasses of the HandlerFactory which add (known, hardcoded) lists of Handlers based on T.
The reason I was doing this was because I initially had this working fine minus one level of generics (i.e. without the Action class), and thought that it wouldn't be too complex to add this class in - it appears I'm wrong!