1

Similar question about var-args in method signatures was asked few times (1, 2) but there is a corner case I don't get it. The compiler can distinguish between int... and long... overloaded method signatures and calls the method with smaller type.

However byte and char are clearly not the same size, yet the compiler complains that below test() method is ambiguous:

static void test(byte... v) { System.out.println("Byte"); }
static void test(char... v) { System.out.println("Char"); }

public static void main(String[] args) {
  test(); // Error:(7, 5) java: reference to test is ambiguous
          // both method test(byte...) in App and method test(char...) in App match
}

Same happens for short... and char... however int... and char... are not ambiguous.

Why is char... considered ambiguous with byte... or short... while by themselves byte... and short... are distinguishable in method signature?

static void test(byte... v) { System.out.println("Byte"); }
static void test(short... v) { System.out.println("Short"); }

public static void main(String[] args) {
  test(); // Byte
}
Karol Dowbecki
  • 43,645
  • 9
  • 78
  • 111
  • 2
    In your example, you didn't pass an argument to test. The compiler has no idea which one you meant to call because it would normally infer that from the argument you passed to it. – Powerlord Jan 09 '19 at 20:51
  • @Powerlord It works if it's `int...` and `long...` so the argument is not always needed. It's `char...` that seems special. – Karol Dowbecki Jan 09 '19 at 20:51
  • 1
    int can be implicitly cast to long, while byte and char aren't compatible with each other. Mainly because char and byte are both 8-bit, but char is unsigned. – Powerlord Jan 09 '19 at 20:54
  • 1
    @SotrisDelimanolis if you believe this is a duplicate kindly please point me to the answer that explains why `char...` is different. – Karol Dowbecki Jan 09 '19 at 20:55
  • 2
    https://stackoverflow.com/a/32293611/438154 There's no "more specific" relation between byte and char, while there is between int and char. – Sotirios Delimanolis Jan 09 '19 at 20:57
  • @SotrisDelimanolis seems that `char` is not a subtype of `int` and `byte`, thanks. – Karol Dowbecki Jan 09 '19 at 20:59
  • 1
    @Powerlord `char` is a 16-bit unsigned integer, not 8-bit. – Lew Bloch Jan 09 '19 at 21:09
  • @LewBloch Whoops, yeah, slip of the brain there. I know Java (and C#) use UTF-16 internally, but I keep thinking of them as UTF-8 because that tends to be the default used when writing to files and things. – Powerlord Jan 09 '19 at 21:15

2 Answers2

0

You didn't include any arguments in the call so how would the compiler know the type?

Also "Otherwise, if the operand is of compile-time type byte, short, or char, it is promoted to a value of type int by a widening primitive conversion (§5.1.2)." https://docs.oracle.com/javase/specs/jls/se10/html/jls-5.html#jls-5.6 The compiler does not see the types as equivalent. It promotes them to int. Since both forms promote to int it doesn't know which to use.

Try explicitly casting the arguments to resolve the ambiguity.

Lew Bloch
  • 3,364
  • 1
  • 16
  • 10
  • Nope, it seems that `char` has no sub-type relation to `byte` and `short` like it has to `int` and `long` as said [in this answer](https://stackoverflow.com/questions/32293476/method-overloading-with-variable-arguments-varargs/32293611#32293611) and [JLS 4.1](https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html#jls-4.10). – Karol Dowbecki Jan 09 '19 at 21:00
  • you have the links in my answer, check it yourself. It seems like a corner case the same with `boolean...`. If you can explain and disprove me I'll accept your answer. Using `char...` and `int...` works, there is a subtype relation as per JLS 4.10 and 4.11. – Karol Dowbecki Jan 09 '19 at 21:04
  • I cited the JLS. What do you mean by "nope"? – Lew Bloch Jan 09 '19 at 21:05
  • As per your JLS how would it work if both `byte...` and `short...` were promoted to `int...`? That would mean the method signature ambiguous but the compiler selects `byte...` as per my answer. Check my second example in my question, it prints `Byte`. – Karol Dowbecki Jan 09 '19 at 21:07
  • 1
    If you don't provide a type in the argument list, or if you provide one that matches more than one signature, you get ambiguity. In your question you didn't show any type information in the method call. That means both method signatures were equally likely candidates. – Lew Bloch Jan 09 '19 at 21:12
-2

The test function is overloaded. You need to pass an appropriate parameter so that the compiler may infer which method to call. Additionally, both byte and char are equally specific primitives for varargs (by that I mean compiler treats them similarly) which thereby causes ambiguity.

Bilal Siddiqui
  • 349
  • 3
  • 17
  • 3
    The intent in the OP's code is to overload it. The confusion comes in with why the overloading has ambiguity. – Makoto Jan 09 '19 at 20:54