"Recursive" generics - aaaargh!

I don't get it - how can I get GenericTest99 to compile? I just want to hold a reference to my abstract type, but I can't do it ... :(publicabstractclass GenericTest99<Eextends Enum><E>>{

publicstaticvoid main (String[] args){

// "Type parameter java.lang.Enum is not within its bound"

GenericTest99<Enum> local;

}

}

[750 byte] By [RGibsona] at [2007-10-3 3:17:01]
# 1

You need to provide a parameter for the Enum that extends Enum. You are trying to use a raw Enum type. Any concrete Enum type will do, or you need to do something like this (untested):

public abstract class GenericTest99<E extends Enum><E>> {

public static void main (String[] args) {

// "Type parameter java.lang.Enum is not within its bound"

GenericTest99<Enum><E>> local;

}

}

dubwaia at 2007-7-14 21:08:32 > top of Java-index,Core,Core APIs...
# 2
Sorry that won't work because that's a static method. You need something else.
dubwaia at 2007-7-14 21:08:32 > top of Java-index,Core,Core APIs...
# 3

Perhaps I over-simplified my example a bit. Obviously I could just dopublic abstract class GenericTest99<E extends Enum><E>> {

public static void main (String[] args) {

// "Type parameter java.lang.Enum is not within its bound"

GenericTest99<?> local;

}

}

Actually what I want to do is create a subclasspublic class GenericTest100 extends GenericTest99<Enum> {

}

but I can't do that either :(

Please don't get hung up on the fact that it's an Enum, this is just a boiled-down testcase - my real code is more complex ...

RGibsona at 2007-7-14 21:08:32 > top of Java-index,Core,Core APIs...
# 4

Again, the problem is that you are trying to use a raw type. You have a few options:

public class GenericTest100<E extends Enum><E>> extends GenericTest99<E>

or

public class GenericTest100 extends GenericTest99<Enum><?>>

or

public class GenericTest100 extends GenericTest99<AConcreteEnumClass>

dubwaia at 2007-7-14 21:08:32 > top of Java-index,Core,Core APIs...
# 5
Why do you feel you need a raw type?
dubwaia at 2007-7-14 21:08:32 > top of Java-index,Core,Core APIs...
# 6

Thanks for your help. But the problem is that I don't (necessarily) want a raw type, I want to parameterise with the superclass (Enum in this example). To take your suggestions one by one:

public class GenericTest100<E extends Enum><E>> extends GenericTest99<E>

This is the best I have so far, except that in my actual code the type parameter E will always be the same type - Enumpublic class GenericTest100 extends GenericTest99<Enum><?>>

Doesn't compilepublic class GenericTest100 extends GenericTest99<AConcreteEnumClass>

No good, I need any Enum.

RGibsona at 2007-7-14 21:08:32 > top of Java-index,Core,Core APIs...
# 7

> Thanks for your help. But the problem is that I

> don't (necessarily) want a raw type, I want to

> parameterise with the superclass (Enum in this

> example). To take your suggestions one by one:

> public class GenericTest100<E extends Enum><E>> extends GenericTest99<E>

>This is the best I

> have so far, except that in my actual code the type

> parameter E will always be the same type -

> Enum

But Enum doesn't extend Enum<Enum>. What is the problem with the declaration above?

dubwaia at 2007-7-14 21:08:32 > top of Java-index,Core,Core APIs...
# 8

> public class GenericTest100 extends GenericTest99<AConcreteEnumClass>

>

> No good, I need any Enum.

Maybe what you need to is to abstract E within a method?abstract class GT {

abstract <E extends Enum><E>> void f(E e);

}

jpmrsta at 2007-7-14 21:08:32 > top of Java-index,Core,Core APIs...
# 9

Actually I think what I really need is to get rid of the recursion - just because Enum is declared recursively, doesn't mean I have to use it recursively:public abstract class GenericTest99<E extends Enum><?>> {

public static void main (String[] args) {

// OK

GenericTest99<Enum><?>> local;

}

}

Thanks for all your suggestions!

RGibsona at 2007-7-14 21:08:32 > top of Java-index,Core,Core APIs...
# 10

By the way, if anyone is still interested, here is somethine closer to my actual problem:class GenericTest<E extends GenericTest><E>> {

}

class Use<U extends GenericTest><U>> {

}

class UseNonGeneric extends Use<GenericTest><?>> {

}

This doesn't compile. What I don't really understand is why replacing with this makes it compileclass GenericTest<E extends GenericTest><E>> {

}

class Use<U extends GenericTest><?>> {

}

class UseNonGeneric extends Use<GenericTest><?>> {

}

Aren't I just specifying the same constraint for U as I was for E?

RGibsona at 2007-7-14 21:08:32 > top of Java-index,Core,Core APIs...
# 11

> Actually I think what I really need is to get rid of

> the recursion - just because Enum is declared

> recursively, doesn't mean I have to use it

> recursively.

And because it is an Enum, you can actually make the assumption that the parametric type is the same as the Enum type, if you need to.

dubwaia at 2007-7-14 21:08:32 > top of Java-index,Core,Core APIs...
# 12

> > Actually I think what I really need is to get rid

> of

> > the recursion - just because Enum is declared

> > recursively, doesn't mean I have to use it

> > recursively.

>

> And because it is an Enum, you can actually make the

> assumption that the parametric type is the same as

> the Enum type, if you need to.

Exactly! The compiler deduces the constraints - that's actually what I wanted, I just didn't know how to ask for it ;)

That said, what am I asking for withclass Use<U extends GenericTest><U>> {

}

in my example above (i.e. the one that doesn't work)?

RGibsona at 2007-7-14 21:08:32 > top of Java-index,Core,Core APIs...
# 13

> Exactly! The compiler deduces the constraints -

> that's actually what I wanted, I just didn't know how

> to ask for it ;)

Actually, I'm pretty sure it doesn't. I said you could assume this because Enums are special. The compiler guarantees they are always self parameterized because it constrains how enums are declared. The recursive declaration does not guarantee this, by itself and the compiler will not make this assumption (even for enums.) This is a common misconception about generics.

Consider the following (look closely at B):

class GenericTest<E extends GenericTest><E>>

{

}

class A extends GenericTest<A>

{

}

class B extends GenericTest<A>

{

}

This will compile but B is parameterized by A. How can that be?

The declaration of GenericType says that all GenericTypes must be parameterized by self-parameterized types. It doesn't say that all GenericTypes are self parameterized. There is no way to write that in Java. This is a subtle distinction and I'm not trying to be obtuse. I just can't think of a better way to say it.

So in the first example you have:

class Use<U extends GenericTest><U>> {

}

This says that Use must be parameterized by a self parameterized GenericTest. Does GenericTest<?> fufill that constriant? No, not necessarily. For example, I could supply B. It's a GenericTest<?> for sure but it is not a U extends GenericTest<U>.

In the second example, you change the declaration of Use to:

class Use<U extends GenericTest><?>> {

}

Now, a B does fit and moreover, any GenericTest will fit.

Am I explaining this well enough?

dubwaia at 2007-7-14 21:08:32 > top of Java-index,Core,Core APIs...
# 14
Beautiful, thank you very much! Next time you're in Paris I'll buy you a beer :)
RGibsona at 2007-7-14 21:08:32 > top of Java-index,Core,Core APIs...
# 15
This is related to the self-type pattern for generics. Take a look at the following for more info about this problem and support (or lack thereof) for it. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6479372
jonbarrila at 2007-7-21 10:08:20 > top of Java-index,Core,Core APIs...