Re: limitations of generic reflection
On Apr 16, 12:08 pm, Owen Jacobson <angrybald...@gmail.com> wrote:
On Apr 16, 12:58 pm, Roger Levy <sinos...@gmail.com> wrote:
I think I have hit up against an interesting limitation of generics in
Java, and I want to confirm that I'm understanding the limitations
properly. I would like to write a method that takes a parameterized
Collection of type C<A>, and apply to each member of the Collection a
method that takes an A and returns a B. The result should be a
Collection of type C<B>. The code would ideally look something like:
public <A, B, C extends Collection> C<B> applyAll(C<A> as,
Function<A,B> f) {
C<B> result = (C<B>) as.getClass().newInstance();
for(A a : as)
result.add(f.apply(a));
return result;
}
with the appropriate exception handling. But it seems like this is
impossible because type parameters themselves cannot be
parameterized. Is there a way around this limitation that I haven't
thought of?
You can parameterize type bounds:
public static
<A, B,
CA extends Collection<A>,
CB extends Collection<B>>
CB apply(
CA as, Function<A, B> f) {
}
however, once you're past that hurdle, you're going to discover that
you can't, eg., do 'new CB', which you'd need for a truly generic
implementation of the map meta-function, nor can you specialize
generics on some arguments the way you could with C++ templates.
This may be a redundant post, but I've found that making the meta-
function evaluation lazy allow you to "code around" the issue somewhat
elegantly.
Assume that your applyAll() returns an Iterable<B> object and computes
f.apply() on demand. In order to get a collection of type C<B>, you
have to do a bit more work by creating an addAll() method. The
framework looks like this (I may be off on exact syntax of the
wildcard bounds, I hope the intention is clear):
public static <A, B> Iterable<B> applyAll( Collection<? extends A> as,
Function<A, B> f ) { // lazy implementation... }
public static <A> void addAll( Collection<? super A> c, Iterable<?
extends A> iterable )
{
for ( A a : iterable )
c.add( a );
}
In your code you might do the following. Assume Set<A> and List<A>
are populated with values.
Function<A, B> myFunc = new MyFunc();
Set<A> sa;
Set<B> sb;
List<A> la;
List<B> lb;
addAll( lb, applyAll( la, myFunc ));
addAll( sb, applyAll( sa, myFunc ));
Like I said, not quite as elegant as one might like, but serviceable.
You might be able to pretty it up some more using the parameterized
type bounds.