Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this Java method call considered ambiguous?

I've come across a strange error message that I believe may be incorrect. Consider the following code:

public class Overloaded {
    public interface Supplier {
        int get();
    }

    public interface Processor {
        String process(String s);
    }

    public static void load(Supplier s) {}
    public static void load(Processor p) {}

    public static int genuinelyAmbiguous() { return 4; }
    public static String genuinelyAmbiguous(String s) { return "string"; }

    public static int notAmbiguous() { return 4; }
    public static String notAmbiguous(int x, int y) { return "string"; }

    public static int strangelyAmbiguous() { return 4; }
    public static String strangelyAmbiguous(int x) { return "string"; }
}

If I have a method that looks like this:

// Exhibit A
public static void exhibitA() {
    // Genuinely ambiguous: either choice is correct
    load(Overloaded::genuinelyAmbiguous); // <-- ERROR
    Supplier s1 = Overloaded::genuinelyAmbiguous;
    Processor p1 = Overloaded::genuinelyAmbiguous; 
}

The error we get makes perfect sense; the parameter to load() can be assigned to either, so we get an error that states the method call is ambiguous.

Conversely, if I have a method that looks like this:

// Exhibit B
public static void exhibitB() {
    // Correctly infers the right overloaded method
    load(Overloaded::notAmbiguous);
    Supplier s2 = Overloaded::notAmbiguous;
    Processor p2 = Overloaded::notAmbiguous; // <-- ERROR
}

The call to load() is fine, and as expected, I cannot assign the method reference to both Supplier and Processor because it is not ambiguous: Overloaded::notAmbiguous cannot be assigned to p2.

And now the weird one. If I have a method like this:

// Exhibit C
public static void exhibitC() {
    // Complains that the reference is ambiguous
    load(Overloaded::strangelyAmbiguous); // <-- ERROR
    Supplier s3 = Overloaded::strangelyAmbiguous;
    Processor p3 = Overloaded::strangelyAmbiguous; // <-- ERROR
}

The compiler complains that the call to load() is ambiguous (error: reference to load is ambiguous), but unlike Exhibit A, I cannot assign the method reference to both Supplier and Processor. If it were truly ambiguous, I feel I should be able to assign s3 and p3 to both overloaded parameter types just as in Exhibit A, but I get an error on p3 stating that error: incompatible types: invalid method reference. This second error in Exhibit C makes sense, Overloaded::strangelyAmbiguous isn't assignable to Processor, but if it isn't assignable, why is it still considered ambiguous?

It would seem that the method reference inference only looks at the arity of the FunctionalInterface when determining which overloaded version to select. In the variable assignment, arity and type of parameters are checked, which causes this discrepancy between the overloaded method and the variable assignment.

This seems to me like a bug. If it isn't, at least the error message is incorrect, since there is arguably no ambiguity when between two choices only one is correct.

like image 525
jigawot Avatar asked Jul 19 '19 18:07

jigawot


People also ask

What does ambiguous mean in Java?

The ambiguities are those issues that are not defined clearly in the Java language specification. The different results produced by different compilers on several example programs support our observations.

What is problem of ambiguity in Java?

Ambiguity errors occur when erasure causes two seemingly distinct generic declarations to resolve to the same erased type, causing a conflict. Here is an example that involves method overloading.

What is ambiguity problem?

You are dealing with ambiguous situations when you see that there is more than one solution to a problem, but you aren't sure which one to do. Or, it might be when you come to a conclusion about a situation, but before you can act on it, the situation has already changed.

What is ambiguity C#?

CsharpProgrammingServer Side Programming. With method overloading, you can have multiple definitions for the same function name in the same scope. The definition of the function must differ from each other by the types and/or the number of arguments in the argument list.


1 Answers

Your question is very similar to this one.

The short answer is:

Overloaded::genuinelyAmbiguous;
Overloaded::notAmbiguous;
Overloaded::strangelyAmbiguous;

all these method references are inexact (they have multiple overloads). Consequently, according to the JLS §15.12.2.2., they are skipped from the applicability check during overload resolution, which results in ambiguity.

In this case, you need to specify the type explicitly, for example:

load((Processor) Overloaded::genuinelyAmbiguous);
load(( Supplier) Overloaded::strangelyAmbiguous);
like image 183
Oleksandr Pyrohov Avatar answered Oct 16 '22 08:10

Oleksandr Pyrohov