Java varargs suck

TLDR; When using varargs in Java 1.6 be aware of problems that will arise when overloading methods that use varargs.

While playing around with Java (1.6) I started using varargs (denoted by type...) which allow you to call a method with variable number of arguments of a given type.

void foo(int... args) {
    for (int i : args) {
        System.out.println(i);
    }
}

foo(); // prints nothing
foo(1); // prints 1
foo(3, 2); // prints 3 & 2

Now, a simple question – before we go further – which method will the compiler use here?

void bar(int i) {} // method A
void bar(long l) {} // method B

bar(5);

Answer is, obviously, method ‘A’. Nothing spectacular: compiler has just chosen the more fitting overload (as in case of long it would have to perform implicit type widening).

Applying the same how-to-choose-an-overload logic we quickly create our overloaded varargs.

void oops(int... i) {} // method A
void oops(long... l) {} // method B

oops(5);

Which method will be chosen by compiler? A? Wrong! B? Wrong! Compiler can’t decide and tells us that it is ‘ambiguous’. Why? There is a bug in current Java implementation which makes the compiler (when deciding on overload) see this:

void oops(int[] i) {} // method A
void oops(long[] l) {} // method B

Which is semi-OK as when working with varargs we are actually dealing with arrays. The problem, however, is that Java doesn’t allow something like:

int[] a = new int[1];
long[] b = new long[1];
a = b; // !!! Error

This is because such assignment will only work with covariant types (if B extends/implements A, than a reference of array of Bs can be assigned to an array of As). In other words: Java tries to determine the proper meaning of ‘5’ (our magic number) and neither long, nor int fit as none of them can be used in both methods (so no meaning is narrower).

Sucks, doesn’t it? If you run into such problem I can only see one way of dealing with it. It isn’t pretty and it defeats the purpose of varargs (which is, IMHO, nifty syntax trick allowing you to call varargs methods easily without syntax boiler-plate). So here it is:

void oops(int... i) {} // method A
void oops(long... l) {} // method B

oops(new int[]{ 5 });

This bug should only appear in Java 1.6 and below, as from Java 1.7 it is fixed.

Advertisements

Tags: , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: