Search code examples
javagenericstype-erasure

Why java compiler doesn't discriminate methods with different types?


I defined following methods.

class Some {

    void doSome(Consumer<? super Other> consumer) {
    }

    <T extends Collection<? super Other>> T doSome(T collection) {
        doSome(collection::add); // <<<<<<<<<<<<<<<<<<<
        return collection;
    }
}

Now the javac complains.

java: reference to getAttributes is ambiguous both method doSome(java.util.function.Consumer<? super Other>) in ... and method doSome(T) in ...Some match

Why javac couldn't discriminate Consumer and Collection?


Solution

  • This is because collection::add is not pertinent to applicability when invoking doSome(T).

    Specifically, it is this case:

    If m is a generic method and the method invocation does not provide explicit type arguments, an explicitly typed lambda expression or an exact method reference expression for which the corresponding target type (as derived from the signature of m) is a type parameter of m.

    m here is doSome, which is a generic method. collection:add is an exact method reference. Its target type is (T) -> boolean (a function that takes in a T and returns boolean). (T) -> boolean includes the type parameter T, so it is not pertinent to applicability.

    "Pertinent to applicability" is Java's way of deciding what argument expressions to consider during overload resolution. It simply doesn't consider some arguments (those that are not pertinent to applicability), because that would make overload resolution too complicated.

    Since collection::add is practically "ignored", doSome(T) is also an applicable method, in addition to doSome(Consumer), which is obviously applicable. Therefore, there is an overload resolution ambiguity.

    I would just add a cast to fix this:

    doSome((Consumer<? super Other>)collection::add);
    

    A cast expression is pertinent to applicability.

    See also this similar question which is about implicitly typed lambda expressions, which are also not pertinent to applicability.