Scala provides a @varargs
annotation that generates a Java varargs forwarder method, which makes it possible to write something like this:
import scala.annotation.varargs
class Foo {
@varargs def foo(args: String*): Unit = {
args.foreach(println)
}
}
And then to call this method from Java without needing to create a scala.Seq
:
Foo foo = new Foo();
foo.foo("a", "b");
Which is pretty nice.
Unfortunately the forwarding part doesn't seem to happen when the method is abstract:
trait Bar {
@varargs def bar(args: String*): Unit
}
class Baz extends Bar {
def bar(args: String*): Unit = {
args.foreach(println)
}
}
Now if we have this Java code:
Bar bar = new Baz();
bar.bar("a", "b");
We get this exception (at runtime):
java.lang.AbstractMethodError: Baz.bar([Ljava/lang/String;)V
We can confirm the problem with javap
:
public interface Bar {
public abstract void bar(java.lang.String...);
public abstract void bar(scala.collection.Seq<java.lang.String>);
}
public class Baz implements Bar {
public void bar(scala.collection.Seq<java.lang.String>);
public Baz();
}
So nope, the forwarder definitely isn't getting implemented.
Putting the annotation on both bar
methods fails to compile:
A method with a varargs annotation produces a forwarder method with the same
signature (args: Array[String])Unit as an existing method.
And of course putting the annotation only on the bar
in Baz
means we can't use the forwarder from a Bar
instance.
This seems like it must be a bug, but it also seems extremely easy to run into, and I'm not seeing anything in the issue tracker. Am I using @varargs
correctly? If so, is there a workaround that would make it do what you'd expect here?
So nope, the forwarder definitely isn't getting implemented. Putting the annotation on both bar methods fails to compile: A method with a varargs annotation produces a forwarder method with the same signature (args: Array[String])Unit as an existing method.
There can be only one variable argument in a method. Variable argument (Varargs) must be the last argument.
The varargs uses ellipsis i.e. three dots after the data type. Syntax is as follows: return_type method_name(data_type... variableName){}
Varargs are useful for any method that needs to deal with an indeterminate number of objects. One good example is String. format . The format string can accept any number of parameters, so you need a mechanism to pass in any number of objects.
I don't know Scala
, but in Java varargs is just an array.
So in Java it will work this way, with one warning:
package tests.StackOverflow.q27052394;
import java.util.Arrays;
public class Runner {
public interface Bar {
public abstract void bar(java.lang.String ... ss);
}
public static class Baz implements Bar {
public void bar(java.lang.String[] array) {
System.out.println(Arrays.toString(array));
}
}
public static void main(String[] args) {
Bar b = new Baz();
b.bar("hello", "world");
}
}
May be if you can fool Scala
the same way, you will overcome the bug.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With