Suspected problem with erasures

Hello,

I have a question regarding java generics.

To explain with an example,

There are three java projects UntypedLib, TypedLib and TypedApp with one class in each project as shown below.

Project TypedApp has a reference to project TypedLib and project TypedLib has a reference to project UntypedLib. More specifically TypedApp must not reference classes from UntypedLib directly.

So, TypedApp -> TypedLib -> UntypedLib (-> indicates project reference).

The idea here is that the class in TypedApp is not directly aware of the (untyped) class UntypedContainer in project UntypedLib. It should only be aware of the (typed) class TypedContainer in project TypedLib, which wraps an instance of UntypedContainer in UntypedLib.

The code snippet below (simplified to focus on problem) doesn't compile at the location (A).

-- Project UntypedLib

package com.test.untyped;

publicclass UntypedContainer{

publicvoid addElement(Object element){

}

}

-- Project TypedLib

package com.test.typed;

import com.test.untyped.UntypedContainer;

publicabstractclass TypedContainer<T>{

private UntypedContainer _delegate =null;

protected TypedContainer(){

}

publicvoid addElement(T typedElement){

_delegate.addElement(typedElement);

}

}

-- Project TypedApp

package com.test.app;

import com.test.typed.TypedContainer;

publicclass StringContainer<String>extends TypedContainer<String>{

// (A) compile error - The type com.test.untyped.UntypedContainer cannot be resolved. It is indirectly referenced from required .class files

publicvoid addStringElement(String s){

}

}

This is the case only if I use java generics in TypedContainer definition. Normally (i.e., in the non-generic case) StringContainer doesn't need UntypedContainer to compile as UntypedContainer is not part of the public signature of class TypedContainer. But it seems even classes in the private parts of TypedContainer are required to compile StringContainer when using generics!!

I did find that within TypedContainer instead of having a private member of type UntypedContainer, if the member is of type UntypedContainer_Proxy - a proxy to UntypedContainer defined within the same project (TypedLib), then the compilation error in StringContainer goes away. UntypedContainer_Proxy defined in project TypedLib looks like,

package com.test.typed;

import com.test.untyped.UntypedContainer;

publicclass UntypedContainer_Proxy{

private UntypedContainer _delegate =null;

publicvoid addElement(Object element){

_delegate.addElement(element);

}

}

But I am not sure why. I suspect this has something to do with erasures in java generics. Somehow looks like UntypedContainer is required during compilation when classes are being erased. Can someone having knowledge of generics/erasures internals suggest what's going on?

Any help appreciated.

regards, alex

Message was edited by:

PeterAhe: added code tags

[4673 byte] By [alexthomas2005a] at [2007-11-26 14:12:30]
# 1

I just created the classes and packages as you described and everything compiled fine. Maybe your original scenario has a different twist on it or the classpath for StringContainer is incorrect.

Btw., in StringContainer you define a Type Parameter named String. I am quite sure, this is not what you intended to do. Quite surely, StringContainer should not be parameterized, should it?

Note: please use the code-tag to make the source code parts of your posting more readable (see formatting guidelines of Java Forums).

stefan.schulza at 2007-7-8 2:01:14 > top of Java-index,Core,Core APIs...
# 2
I cannot reproduce the problem using this sequence of commands:javac UntypedContainer.java -d UntypedLibjavac -cp UntypedLib TypedContainer.java -d TypedLibjavac -cp TypedLib StringContainer.java
PeterAhea at 2007-7-8 2:01:14 > top of Java-index,Core,Core APIs...
# 3

> public class StringContainer<String> extends TypedContainer<String> {

This won't be helping. You probably don't want a type variable with the same name as a class in the type system. You probably want:

public class StringContainer extends TypedContainer<String> {

(i.e. StringContainer doesn't need to be parameterised)

dannyyatesa at 2007-7-8 2:01:14 > top of Java-index,Core,Core APIs...
# 4

> This won't be helping. You probably don't want a type

> variable with the same name as a class in the type

> system. You probably want:

This is a big gotcha in generics. I don't know what the solution is but I wish there was some way to prevent this type of thing.

Maybe a PMD or similar tool could have a check for this.

dubwaia at 2007-7-8 2:01:14 > top of Java-index,Core,Core APIs...
# 5

> This is a big gotcha in generics. I don't know what

> the solution is but I wish there was some way to

> prevent this type of thing.

>

> Maybe a PMD or similar tool could have a check for

> this.

What should that tool check for other than what java provides, i.e., a warning that the name is hiding a class? It's the same with variable names, so it's not new with Generics.

stefan.schulza at 2007-7-8 2:01:14 > top of Java-index,Core,Core APIs...
# 6

> > This is a big gotcha in generics. I don't know

> what

> > the solution is but I wish there was some way to

> > prevent this type of thing.

> >

> > Maybe a PMD or similar tool could have a check for

> > this.

>

> What should that tool check for other than what java

> provides, i.e., a warning that the name is hiding a

> class? It's the same with variable names, so it's not

> new with Generics.

Does the compiler issue a warning for this? I wasn't aware of that.

In any event when someone sees String s, they

are usually not going to check that String isn't a

type parameter name. I've seen a lot of people

get very confused about this. Often, it's more of an

issue with types declared on the method. I've seen

(and probably done it my self) quite a few people think

they've bent generics to do something really slick

with generics when they've just created a type with

the name String.

dubwaia at 2007-7-8 2:01:14 > top of Java-index,Core,Core APIs...
# 7

> Does the compiler issue a warning for this? I wasn't

> aware of that.

Well, here it does: "The type parameter String is hiding the type String".

May depend on the compiler settings, of course.

> In any event when someone sees String s, they

> are usually not going to check that String isn't a

> type parameter name. I've seen a lot of people

> get very confused about this. Often, it's more of

> an

> issue with types declared on the method. I've seen

> (and probably done it my self) quite a few people

> think

> they've bent generics to do something really slick

> with generics when they've just created a type with

> the name String.

Of course, it's confusing. And surely bad code style. But that is up to the programmer, as the problem for using String as Type Parameter name holds for any other class name. It is a bit worse than declaring a variable, e.g. String Number;

, as they also stand for types. But I doubt you could do more than a warning (or only for a limited set of specific names), as class names can be chosen freely, too.

stefan.schulza at 2007-7-8 2:01:14 > top of Java-index,Core,Core APIs...
# 8

> Of course, it's confusing. And surely bad code style.

> But that is up to the programmer, as the problem for

> using String as Type Parameter name holds for any

> other class name. It is a bit worse than declaring a

> variable, e.g. String Number;, as they

> also stand for types. But I doubt you could do more

> than a warning (or only for a limited set of specific

> names), as class names can be chosen freely, too.

That's I guess where I was thinking a PMD or similar tool might come in.

You could create a rule that says types must be in all caps. Generally

class names are CamelCase. I've have seen people use CAPS

for acronymns but I disagree with that practice because it doesn't work

well with CamelCase. Instead I treat acronmyns as normal words for

in CamelCase. If you followed that rule, then a tool like PMD could just

cough on any CamelCase type names.

dubwaia at 2007-7-8 2:01:14 > top of Java-index,Core,Core APIs...
# 9
Well, in that case, one easily confuses type variables with constants, don't you think? I actually like the way of only using one-uppercase-lettered variable names, which bears few conflict. One should not need to have the use for more than 26 type variables per class definition, I
stefan.schulza at 2007-7-8 2:01:14 > top of Java-index,Core,Core APIs...
# 10

Hello all,

Firstly thank you all for your replies.

There is a typo in my code listing earlier - it should indeed be,

public class StringContainer extends TypedContainer<String>

Sorry about this and for leading some of you guys in the wrong direction. The code compiles successfully from the command line as noted by PeterAhe. The classpath references are also correct.

But the error remains in latest eclipse IDE (this was not mentioned clearly by me). Try adding the jar/folder/project containing TypedContainer.class to the classpath references of project containing StringContainer and check if you see the error.

In my case, the StringContainer code is actually generated using a code-generator plugin written for eclipse and hence compiling the generated code separately from the command line may not be an option.

I found later that this is not a problem in NetBeans IDE. May be this is an eclipse bug and needs to be investigated separately, but would nevertheless appreciate if any of the eclipse users can confirm this behavior and give your opinions on this.

thanks again,

Alex

alexthomas2005a at 2007-7-8 2:01:14 > top of Java-index,Core,Core APIs...
# 11
Phew, if the class-file is generated it might be a refresh problem within eclipse not recognizing the new file in the path. Did you try to do a project refresh after the generation process? eclipse caches the file structures.
stefan.schulza at 2007-7-8 2:01:14 > top of Java-index,Core,Core APIs...
# 12

> Well, in that case, one easily confuses type

> variables with constants, don't you think? I actually

> like the way of only using one-uppercase-lettered

> variable names, which bears few conflict. One should

> not need to have the use for more than 26 type

> variables per class definition, I think.

I agree. I'm not going to say that someone would never have a good reason

to use more, though. But even if you never used more than one letter, a PMD

rule that checked for lowercase in type declarations would catch the error.

dubwaia at 2007-7-8 2:01:14 > top of Java-index,Core,Core APIs...
# 13

> I found later that this is not a problem in NetBeans

> IDE. May be this is an eclipse bug and needs to be

> investigated separately, but would nevertheless

> appreciate if any of the eclipse users can confirm

> this behavior and give your opinions on this.

Eclipse's compiler and the JDK compiler have both had bugs with regard to generics. Sometimes Eclipse gets it right, sometimes it's wrong. The issues have been clearing up over time. I know I've had an issue where Eclipse won't let me use switch with enums which should be allowed IIRC.

Also, along with what Stephan suggested, try a clean on your project in Eclipse. Eclipse sometimes gets 'stuck' in an inconsistent state or something. After you do your clean check the 'problems' view too. If there's something preventing compilation, Eclipse won't tell you other than in that view.

dubwaia at 2007-7-8 2:01:14 > top of Java-index,Core,Core APIs...