I've got two pieces of code; one of them compiles without error, and the
other one doesn't. I can't figure out why. Here's the code snippets:
<compilesFine>
import java.util.Vector;
public class HistoryObjectsManager {
public void doSomethingWithRecord(Record record) {
for (Integer integer : record.getVector()) {
//Does nothing.
}
}
}
abstract class Record {
public Vector<Integer> getVector() {
return new Vector<Integer>();
}
}
</compilesFine>
<generatesCompileError>
import java.util.Vector;
public class HistoryObjectsManager {
public void doSomethingWithRecord(Record record) {
for (Integer integer : record.getVector()) {
//Does nothing.
}
}
}
abstract class Record<A> {
public Vector<Integer> getVector() {
return new Vector<Integer>();
}
}
</generatesCompileError>
The only difference between the two is that Record has a type parameter.
The compile error I get is:
<errorMessage>
HistoryObjectsManager.java:5: incompatible types
found : java.lang.Object
required: java.lang.Integer
for (Integer integer : record.getVector()) {
^
</errorMessage>
I'm using JavaC 1.5.0.
Is this a bug in the compiler or a misunderstanding on my part about
generics?
- Oliver
John C. Bollinger - 02 Nov 2005 06:43 GMT
> I've got two pieces of code; one of them compiles without error, and the
> other one doesn't. I can't figure out why. Here's the code snippets:
[quoted text clipped - 50 lines]
> Is this a bug in the compiler or a misunderstanding on my part about
> generics?
I don't know, but I have seen similar. It seems that the compiler
ignores all type parameters associated with a "raw" parameterized type,
such as you have in the second case. This may be intended to provide
compilation diagnostics equivalent to those of a pre-1.5 compiler when
compiling mixed 1.[234]/1.5 codes. In any case, if you don't care what
the Record's type parameter is then the most appropriate Java 1.5 way to
write the method is:
public void doSomethingWithRecord(Record<?> record) {
for (Integer integer : record.getVector()) {
//Does nothing.
}
}
I haven't actually tested it, but I bet it will do what you want. It
has the further advantage of documenting that it in fact works with a
Record type having any type argument, which your original code does not do.

Signature
John Bollinger
jobollin@indiana.edu
Oliver Wong - 02 Nov 2005 16:15 GMT
> In any case, if you don't care what the Record's type parameter is then
> the most appropriate Java 1.5 way to write the method is:
[quoted text clipped - 8 lines]
> the further advantage of documenting that it in fact works with a Record
> type having any type argument, which your original code does not do.
Yeah, this does fix the compile error and does seem to reflect the
"intent" of the code. Thanks.
- Oliver
Ingo R. Homann - 02 Nov 2005 11:12 GMT
Hi,
> <generatesCompileError>
> import java.util.Vector;
[quoted text clipped - 13 lines]
> }
> </generatesCompileError>
This should work:
public void doSomethingWithRecord(Record<Integer> record) {
Ciao,
Ingo
Ross Bamford - 02 Nov 2005 13:05 GMT
> import java.util.Vector;
> public class HistoryObjectsManager {
[quoted text clipped - 9 lines]
> }
> }
Heres how I see it. In the version above, Record is a generic class. When
you say:
public void doSomethingWithRecord(Record record) {
for (Integer integer : record.getVector()) {
//Does nothing.
}
}
You're not just saying 'any type of record', but 'an untyped record'.
Either the compiler assumes that you're not interested in generics at all,
or it has no way to distinguish between literal types (like <Integer>) and
types that are inferred (e.g. if instead of integer it was <? super
Integer>). So, everything behaves as if there are no parameters, and the
vector returns a untyped iterator (of Object).
If you change the method:
public void doSomethingWithRecord(Record<?> record) {
for (Integer integer : record.getVector()) {
//Does nothing.
}
}
You'll find it works, because you're now saying 'any type of Record'.

Signature
Ross Bamford - rosco@roscopeco.remove.co.uk
Oliver Wong - 02 Nov 2005 16:10 GMT
>> import java.util.Vector;
>> public class HistoryObjectsManager {
[quoted text clipped - 35 lines]
>
> You'll find it works, because you're now saying 'any type of Record'.
Notice though that the getVector() method returns a Vector<Integer>,
regardless of the type of A. This was a simplified code snippet; in the
original code, A did affect some methods, but it wasn't affecting the
getVector() method. I.e. the original code looked something like this:
<originalCode>
public class Record<A> {
private A myValue;
public Vector<Integer> getVector() {
return null;
}
public A getInternalValue() {
return myValue;
}
}
</originalCode>
So no matter WHAT kind of record (whether it be Record<Object>,
Record<String> or anything else), Record's .getVector() method should ALWAYS
return a Vector<Integer>.
- Oliver