views:

45

answers:

2

I get the following error message (reduced to the important part) when I'm compiling my classes:

reference to keySet is ambiguous, both method keySet() in
java.util.SortedMap<E,capture#614 of ?> and method keySet() in
test.ImmutableMap<E,capture#614 of ?> match
    return map.keySet().iterator();
              ^

map is of type ImmutableSortedMap<E, ?> and the definition of immutable classes looks like:

public interface ImmutableMap<K, V>
    extends Map<K, V> {
  @Override
  public ImmutableSet<K> keySet();
  ...
}
public interface ImmutableSortedMap<K, V>
    extends ImmutableMap<K, V>, SortedMap<K, V> {
  ...
}
public interface ImmutableSet<E>
    extends Set<E> {
  ...
}

The error appears when I'm compiling using an ANT script or manually, but not in eclipse. I tried it with sun 1.6.0 and icedtea6 1.8.1.

Is there something obvious I'm missing or is there an option that may be set somewhere in eclipse to allow the compilation? The thing is that, right now, I can run the tests in eclipse, but I cannot compile the project outside eclipse.


EDIT: the answer

It seems that some compiler versions have problems with multiple inheritance like that. The solution is to override the method one more time in the sub-class inheriting from other interfaces that have a common super-interface and that override themselves the method.

public interface ImmutableSortedMap<K, V>
    extends ImmutableMap<K, V>, SortedMap<K, V> {
  // adding this method solves the problem
  @Override
  public ImmutableSet<K> keySet();
}

By the way, this is the diamon problem.

A: 

both interfaces ImmutableMap and SortedMap have a method named "keySet()" so the compiler can't figure out wich one to call. Change the method's name in your interface ;)

Aymen
If the methods match, then that is not a problem.
Tom Hawtin - tackline
Instead of changing the name, redeclaring the method in the subclass solved the problem.
Chris
+1  A: 

It looks to me, ImmutableMap#keySet has wrong return type. It should be Set<K> or ImmutableSet<K>.
Or, if you want to return a set of pairs, override Map#entrySet instead.

There's nothing wrong if interace A extends interfaces B and C and both B and C has method with same signature (doIt(String param1, int param2)). But return types of B#doIt and C#doIt should be compatible. If B#doIt returns String and C#doIt returns int, then we can't combine those two methods in one class.

Oh, and no idea why it compiles under Eclipse.

Nikita Rybak
I had the same error with entrySet and I mistyped the generic type of the method. (I've corrected the question)
Chris
@Chris Then there's nothing wrong with the sample you provided (except that you could use standard immutable wrappers from jdk). Can you show how keySet is implemented? (its declaration there)
Nikita Rybak
I edited the question and it seems that it is a problem with the compiler which needs to be explicitly told the signature of the method in ImmutableSortedMap.I don't use the wrappers because the cost to create a new immutable structure which is the original structure with just some modified elements needs a copy of the entire structure. The implementation is not revelant here and uses lot of other functions... it's too big to put it here.
Chris