Strange compile error involving generics (short code snippet included)

Discussion in 'Java' started by Oliver Wong, Nov 1, 2005.

  1. Oliver Wong

    Oliver Wong Guest

    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
     
    Oliver Wong, Nov 1, 2005
    #1
    1. Advertising

  2. Re: Strange compile error involving generics (short code snippetincluded)

    Oliver Wong wrote:
    > 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?


    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.

    --
    John Bollinger
     
    John C. Bollinger, Nov 2, 2005
    #2
    1. Advertising

  3. Re: Strange compile error involving generics (short code snippetincluded)

    Hi,

    Oliver Wong wrote:
    > <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>


    This should work:

    public void doSomethingWithRecord(Record<Integer> record) {

    Ciao,
    Ingo
     
    Ingo R. Homann, Nov 2, 2005
    #3
  4. Oliver Wong

    Ross Bamford Guest

    On Tue, 01 Nov 2005 21:46:11 -0000, Oliver Wong <>
    wrote:

    > 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>();
    > }
    > }


    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'.

    --
    Ross Bamford -
     
    Ross Bamford, Nov 2, 2005
    #4
  5. Oliver Wong

    Oliver Wong Guest

    "Ross Bamford" <> wrote in message
    news:eek:...
    > On Tue, 01 Nov 2005 21:46:11 -0000, Oliver Wong <>
    > wrote:
    >
    >> 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>();
    >> }
    >> }

    >
    > 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'.


    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
     
    Oliver Wong, Nov 2, 2005
    #5
  6. Oliver Wong

    Oliver Wong Guest

    "John C. Bollinger" <> wrote in message
    news:dk9jk5$dib$...
    >
    > 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.


    Yeah, this does fix the compile error and does seem to reflect the
    "intent" of the code. Thanks.

    - Oliver
     
    Oliver Wong, Nov 2, 2005
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Rhino
    Replies:
    11
    Views:
    661
    Chris Uppal
    Feb 6, 2006
  2. Shimon
    Replies:
    0
    Views:
    328
    Shimon
    Apr 25, 2006
  3. Carlos Ribeiro
    Replies:
    10
    Views:
    511
    Peter Hansen
    Sep 15, 2004
  4. David Geering

    longs, long longs, short short long ints . . . huh?!

    David Geering, Jan 8, 2007, in forum: C Programming
    Replies:
    15
    Views:
    595
    Keith Thompson
    Jan 11, 2007
  5. Novice
    Replies:
    7
    Views:
    327
    Roedy Green
    Oct 30, 2011
Loading...

Share This Page