Compiler bug? "reference to addAll is ambiguous"

O

Oliver Wong

I've got a piece of code which compiles fine in Eclipse, but seems to have
problem with Sun's compiler. I'm not sure of the exact version of Sun's
compiler being used, the error was reported to me by a coworker. Here's
the error message:

<errorMessage>
Rewriting\src\java\gov\sc\eip\report\birt\ChangesRowGenerator.java:116:
reference to addAll is ambiguous, both method
addAll(java.util.Collection<? extends E>) in
java.util.Collection<capture#420 of ? super
gov.sc.eip.report.birt.items.ChangeRow> and method
addAll(java.util.Collection<? extends E>) in java.util.List<capture#420 of
? super gov.sc.eip.report.birt.items.ChangeRow> match
</errorMessage>

I didn't post an SSCCE because (1) I'm not sure I'm allowed to and (2)
because I think the error message is sufficient to demonstrate that there
may be a bug... either in the compiler, or in my understanding of
overwriting.

It seems to me that the error message is saying that it cannot determine,
from my code, whether the .addAll() which I am calling refers to the
..addAll in java.util.Collection or the .addAll() in java.util.List. But
doesn't the .addAll() in java.util.List overwrite the .addAll() in
java.utilCollection, so that the "List-version" always be the one invoked?
And anyway, aren't these both interfaces, and thus provide zero
implementation, and thus it doesn't really matter which of these two
methods are being called, since they will eventually point to the exact
same implementation depending on what underlying concrete type is
involved?

In case it's relevant, I'll include the statement where the error is
generated:

<veryShortSnippet>
rows.addAll(getRowForGenericChange(changeSet.getCountyChange(),
CommonFieldNamesEnum.COUNTY.getCode()));
</veryShortSnippet>

"rows" is a parameter past into the method of type "List<? super
ChangeRow>". As you can see, I'm not doing any weird casting to bypass the
overwriting (e.g. I'm not doing something like
"((Collection)rows).addAll(whatever)", which in my opinion should work
even if I did do that anyway).

- Oliver
 
T

Tom Hawtin

Oliver said:
<errorMessage>
Rewriting\src\java\gov\sc\eip\report\birt\ChangesRowGenerator.java:116:
reference to addAll is ambiguous, both method
addAll(java.util.Collection<? extends E>) in
java.util.Collection<capture#420 of ? super
gov.sc.eip.report.birt.items.ChangeRow> and method
addAll(java.util.Collection<? extends E>) in java.util.List<capture#420 of
? super gov.sc.eip.report.birt.items.ChangeRow> match
</errorMessage>

I assume E extends ChangeRow.
And anyway, aren't these both interfaces, and thus provide zero
implementation, and thus it doesn't really matter which of these two
methods are being called, since they will eventually point to the exact
same implementation depending on what underlying concrete type is
involved?

It doesn't matter if the (non-private, non-static) method is being
called is defined in an interface or a class (other than the instruction
is invokeinterface vs invokevirtul).
<veryShortSnippet>
rows.addAll(getRowForGenericChange(changeSet.getCountyChange(),
CommonFieldNamesEnum.COUNTY.getCode()));
</veryShortSnippet>

That rules out the only tenuous explanation I could think of (that it
was something wacky to do with inner classes).
"rows" is a parameter past into the method of type "List<? super
ChangeRow>". As you can see, I'm not doing any weird casting to bypass the
overwriting (e.g. I'm not doing something like
"((Collection)rows).addAll(whatever)", which in my opinion should work
even if I did do that anyway).

The obvious work around is to assign rows to a Collection<? super
ChangeRow> variable. (I assume ChangeRow has no generic parameters.)

Tom Hawtin
 
O

Oliver Wong

Tom Hawtin said:
I assume E extends ChangeRow.

There is no actual "E" in my code. I think the "E" comes from Sun's
implementation onf java.util.List.class and java.util.collection.class.
The variable "rows" involed here is declared as "List<? super ChangeRow>
rows", so I guess "E" is "? super ChangeRow" and so the method addAll's
generic type is "? extends (? super ChangeRow)" (not sure if that even
makes sense). But anyway, I think, from a language-specification point of
view, the error doesn't really have anything to do with generics.

However, from a practical-implementation point of view, if this is indeed
a bug in the compiler and not in my understanding, I can imagine how
throwing generics in the mix might have introduced this bug.
It doesn't matter if the (non-private, non-static) method is being
called is defined in an interface or a class (other than the instruction
is invokeinterface vs invokevirtul).

Right, but what I meant is that we have a class hierarchy like:

public interface Collection<E> {
public void addAll(Collection<? extends E> stuffToAdd);
}

public interface List<E> extends Collection {
public void addAll(Collection<? extends E> stuffToAdd);
}

public class ArrayList<E> implements List<E> {
/* etc. */
}

so that when you have code like:

public void myMethod(List<? super ChangeRow> rows) {
rows.addAll(getSomeData());
}

public List<? super ChangeRow> getSomeData() {
List<ChangeRow> returnValue = new ArrayList<ChangeRow>();
return returnValue;
}

there should be no reason to ask whether the .addAll() refers to the one
in Collection, or the one in List. I've got a
multiple-interface-inheritance situation, and *not* a
multiple-implementation-inheritance situation; thus the "diamond problem"
does not come up, and thus there should be no ambiguity about which method
I'm invoking when I call .addAll().
That rules out the only tenuous explanation I could think of (that it
was something wacky to do with inner classes).

Right, the code is structurally very straightforward (it's essentially
a CRUD web app). No inner classes anywhere to be seen.
The obvious work around is to assign rows to a Collection<? super
ChangeRow> variable. (I assume ChangeRow has no generic parameters.)

I'll give that a try and ask my coworker to compile again and see what
happens.

- Oliver
 
O

Oliver Wong

Oliver Wong said:
I've got a piece of code which compiles fine in Eclipse, but seems to
have problem with Sun's compiler. I'm not sure of the exact version of
Sun's compiler being used, the error was reported to me by a coworker.
Here's the error message:

At this point, I'm relatively confident it's a compiler bug. I can't
reproduce the error using 1.5.0_06-b05, 1.6.0-b105, 1.6.0_01-b06 nor
1.6.0_02-b06. My coworker's version is 1.6.0_02-b05 which I can't seem to
find online.

- Oliver
 
S

Steven Simpson

Oliver said:
reference to addAll is ambiguous, both method
addAll(java.util.Collection<? extends E>) in
java.util.Collection<capture#420 of ? super
gov.sc.eip.report.birt.items.ChangeRow> and method
addAll(java.util.Collection<? extends E>) in java.util.List<capture#420 of
? super gov.sc.eip.report.birt.items.ChangeRow> match

Could it be this?:

<http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6356673>

That's for a 1.5 version, but note the comments and one of the related
bugs. It's been present in all the 1.6 versions I've tried.

As it's a List, perhaps you could try using addAll(int, ...) as a
workaround.
 
R

Roedy Green

Rewriting\src\java\gov\sc\eip\report\birt\ChangesRowGenerator.java:116:
reference to addAll is ambiguous, both method
addAll(java.util.Collection<? extends E>) in
java.util.Collection<capture#420 of ? super
gov.sc.eip.report.birt.items.ChangeRow> and method
addAll(java.util.Collection<? extends E>) in java.util.List<capture#420 of
? super gov.sc.eip.report.birt.items.ChangeRow> match
</errorMessage>

This sort of problem happens when you use java.util.List and
java.awt.List in the same program. You have to fully qualify each
reference with package name to avoid ambiguity.

However, your case is more peculiar.

It looks as if are doing x.addall(

where x is both a Collection and a List.

Yet this should not cause trouble. List is a subinterface of
Collection.

The practical way out of this is to define x concretely, e.g.

ArrayList<Thing> x = new ArrayList<Thing>( 2000);
x.addAll (myThingCollection);

Please post code, at least your imports, where you define x, where
you define the collection and the type of the collection and the
addall. This is intriguing.
 
O

Oliver Wong

Steven Simpson said:
Could it be this?:

<http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6356673>

That's for a 1.5 version, but note the comments and one of the related
bugs. It's been present in all the 1.6 versions I've tried.

It looks very similar to my issue, except that I think my situation is
much simpler than the part which goes "<L extends List<? super A>>";
instead said:
As it's a List, perhaps you could try using addAll(int, ...) as a
workaround.

I couldn't get the bug to reproduce on my machine, so I advised my
coworker to try updating to a newer version of Java. He hasn't told me
whether or not that made the problem go away. If it's still present, your
solution sounds like the least messy one so far.

- Oliver
 
O

Oliver Wong

Roedy Green said:
This sort of problem happens when you use java.util.List and
java.awt.List in the same program. You have to fully qualify each
reference with package name to avoid ambiguity.

However, your case is more peculiar.

Right, there's no reference to java.awt.* at all: It's a web
application, not a desktop one.
It looks as if are doing x.addall(

where x is both a Collection and a List.

Yet this should not cause trouble. List is a subinterface of
Collection.

Agreed.
The practical way out of this is to define x concretely, e.g.

ArrayList<Thing> x = new ArrayList<Thing>( 2000);
x.addAll (myThingCollection);

Please post code, at least your imports, where you define x, where
you define the collection and the type of the collection and the
addall. This is intriguing.

We (the company I work for) actually don't fully own the code. It's
shared among a couple of developers working for several different
companies all collaborating on one big project, so I'm not sure I can post
the full code. Furthermore, since I can't actually replicate the problem
on my machine, I can't really compose an SSCCE, because I can't test
whether the parts which I consider "unimportant" actually affect the bug
or not: No matter what I add or remove, the code compiles fine on *my*
machine.

- Oliver
 
S

Steven Simpson

Oliver said:
It looks very similar to my issue, except that I think my situation is
much simpler than the part which goes "<L extends List<? super A>>";
instead, it's simply "List<? super ActualClassNotATypeVariable>"

Note the GenericCaptureAddingTest example further down, which I think is
more similar (although it's for Set, but I get the same problem when I
change it to List).
 
T

Twisted

This sort of problem happens when you use java.util.List and
java.awt.List in the same program. You have to fully qualify each
reference with package name to avoid ambiguity.

While Java 7 proposed features remains a hot topic, let's propose
making this legal:

import java.util.List;
import java.awt.List AList;

....

List x = new LinkedList(); // a java.util.List
AList y = new AList(); // a java.awt.List

It just means adding an alternate legal form of import statement,
without losing backward source compatibility:

import fully-qualified-class alias;

and the stock import is then essentially just an elliptical form that
defaults "alias" to the last chunk of the fq class name.
 
R

Roedy Green

While Java 7 proposed features remains a hot topic, let's propose
making this legal:

import java.util.List;
import java.awt.List AList;

that is reminiscent of the way Eiffel lets you get around the problem
of duplicate names with multiple inheritance.
 
T

Twisted

that is reminiscent of the way Eiffel lets you get around the problem
of duplicate names with multiple inheritance.

Yes, but multiple inheritance is evil, and this is closer to some C++
"using" and "typedef" usages and won't introduce any real cruftiness.

Well, unless someone goes out of their way with gratuitously aliasing
common standard library classes in e.g. java.util or java.io to wacky
names just to be a pain or maybe in the vain hope of job security
through indispensibility if the code is ever to be maintained; but
that's always going to be possible, whether by hairy use of imports,
hairy entangled masses of nested and anonymous inner classes, or just
hairy entangled messes of for and while loops full of break and
continue statements to recreate the bad old days of GOTO-ridden ROM-
BASIC-inspired spaghetti code.

Mind you they should get extra bonus points* for confusingly aliasing
classes in java.lang, especially String and the basic exception
classes, and referring to each under both the usual name AND the alias
and picking which to use at each site in a random fashion.

* Each bonus point redeemable for one (1) free pink slip of course.
 
P

Piotr Kobzda

Steven said:
Note the GenericCaptureAddingTest example further down, which I think is
more similar (although it's for Set, but I get the same problem when I
change it to List).

I think, that's the same bug.

Just for fun, I've slightly modified that example to reflect as close as
possible the Oliver's situation, here is the SSCCE:


import java.util.List;

public abstract class Test {

public interface ChangeRow {}

public void addData(List<? super ChangeRow> rows) {
rows.addAll(getSomeData());
}

protected abstract List<? extends ChangeRow> getSomeData();
}


On my machine (Windows XP, Intel 32bit), compiling the above example
produce the following output:

Test.java:8: reference to addAll is ambiguous, both method
addAll(java.util.Collection<? extends E>) in
java.util.Collection<capture#156 of ? super Test.ChangeRow> and method
addAll(java.util.Collection<? extends E>) in java.util.List<capture#156
of ? super Test.ChangeRow> match
rows.addAll(getSomeData());
^
1 error


This bug is reproducible using 1.6.0-beta2-b86, 1.6.0-b105, and
1.6.0_02-b06. Example compiles successfully with 1.5.0_04-b05,
1.5.0_06-b05, and 1.6.0-beta2-b73. (I have no other Java 5+ VMs
installed to test it)


piotr
 
O

Oliver Wong

Piotr Kobzda said:
Just for fun, I've slightly modified that example to reflect as close as
possible the Oliver's situation, here is the SSCCE:


import java.util.List;

public abstract class Test {

public interface ChangeRow {}

public void addData(List<? super ChangeRow> rows) {
rows.addAll(getSomeData());
}

protected abstract List<? extends ChangeRow> getSomeData();
}

Bingo, you've found it. I tried your example, and it compiles fine
with:

javac 1.5.0_06

But triggers the bug in:

javac 1.6.0
javac 1.6.0_01
javac 1.6.0_02

- Oliver
 
S

Steven Simpson

Oliver said:
triggers the bug in:

javac 1.6.0
javac 1.6.0_01
javac 1.6.0_02

FYI, I submitted a new bug report to Sun on this just before this thread
started, and they've got back to me to say it has been fixed in JDK7,
and will also be fixed in a future JDK6 update.
 
T

Twisted

FYI, I submitted a new bug report to Sun on this just before this thread
started, and they've got back to me to say it has been fixed in JDK7,
and will also be fixed in a future JDK6 update.

I don't know about you, but personally, I find "a future JDK6 update"
to be somewhat vague and unhelpful ...
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top