Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abstract methods and the varargs annotation

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?

like image 435
Travis Brown Avatar asked Nov 21 '14 00:11

Travis Brown


People also ask

Can Varargs be used in abstract method?

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.

At which position should Varargs be placed in a parameterized method?

There can be only one variable argument in a method. Variable argument (Varargs) must be the last argument.

Which is the correct declaration of Varargs method?

The varargs uses ellipsis i.e. three dots after the data type. Syntax is as follows: return_type method_name(data_type... variableName){}

Is it good to use varargs in java?

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.


1 Answers

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.

like image 180
Suzan Cioc Avatar answered Oct 10 '22 01:10

Suzan Cioc