2010-06-22 16 views
9

J'ai 2 méthodes simples dans une classe de bibliothèque scala:Comment déclarer la méthode scala de sorte qu'il peut être appelé à partir de Java en utilisant le style varargs

class Foo { 
    def bar(args : String*) : Unit = println("Foo.bar with: " + args) 
    def bar(args : Array[String]) : Unit = bar(args.toSeq : _*) 
} 

Tout cela Compile bien. Je mets alors cela dans une bibliothèque foo.jar et essayer de compiler la pièce suivante de Java:

import Foo 
public class Test { 

    public static void main(String[] args) { 
     Foo foo = new Foo(); 
     foo.bar("Hello", "World"); //DOES NOT COMPILE 
    } 
} 

Je peux remplacer la ligne incriminée avec:

foo.bar(new String[] { "Hello", "World" }); //OK 

Mais cela semble vaincre le point. Comment puis-je l'appeler à partir de Java en utilisant une syntaxe similaire à Java Varargs?

+0

est peut-être une faute de frappe mais classe 'foo' n'a pas méthode' foo'. –

+0

A bientôt - faute de frappe –

+0

Je me trompe manifestement dans ce que j'ai dit, même si j'avoue que cela me rend confus. Je supprime ma réponse pour éviter de répandre de la désinformation. –

Répondre

3

2.8 (dunno environ 2,7), si vous remplacez une méthode varargs d'un parent Java, ou mettre en œuvre une méthode varargs à partir d'une interface Java, le compilateur Scala va générer deux méthodes , un pour Scala, un pour Java. Celui de Java - comme vous pouvez le voir en inspectant le bytecode - prend simplement le tableau varargs et l'enveloppe, puis passe le WrappedArray à la version Scala qui attend un Seq.

S'il existe un moyen de forcer le compilateur à générer le redirecteur dans d'autres circonstances, je ne le sais pas. Je doute qu'il existe. On dirait que fournir un moyen de le demander (une annotation, je suppose) serait une demande d'amélioration raisonnable.

1

Pas tout à fait certain mais je pense que varargs dans Scala utilise des séquences et sont différentes de l'implémentation java. Je pense que la meilleure façon d'accomplir ce que vous voulez est de sous-classe de la classe Foo scala en Java et ajouter une méthode de barre qui prend un Java vararg-à-dire

public class JavaFoo extends Foo { 
    public void bar(String... args) { 
     super.bar(args) 
    } 
} 

La méthode vararg JavaFoo peut alors être appelé en utilisant la syntaxe vararg en Java .

Hope it helps :)

+1

Hmmm ... essayé la suggestion de Daniel, mais je ne pouvais pas obtenir ça pour travailler en utilisant scala 2.8 beta. La compilation est-elle à la fois une vararg java et une scala vararg quelque chose qui vient d'être ajouté récemment? La décompilation du bytecode donne juste une classe Foo avec une méthode de barre de vide publique (Seq args) ... –

0

Malgré l'indication utile sur l'utilisation d'une interface Java pour forcer le compilateur Scala à être "compatible", je n'ai tout simplement pas réussi à faire fonctionner mon code. Finalement, il m'est apparu que les méthodes ont été déclarées sur un objet Scala , ce qui signifie qu'elles sont en fait statiques, et vous ne pouvez pas spécifier de méthodes statiques dans une interface, donc le compilateur ignorait simplement le fait que l'objet implémentait l'interface . Heureusement pour moi, il y a une solution de rechange. Au lieu d'appeler la méthode statique directement à partir de Java comme ceci:

CLASS.method(x,y,z) 

Vous devez appeler comme ceci:

CLASS$.MODULE$.method(x,y,z) 

Cela signifie que vous êtes en fait d'accéder au objet singleton comme une instance appelée par un champ statique, et puisqu'il s'agit d'une instance, et implémente l'interface java, il le compilateur fait son travail correctement et implémente la méthode varargs afin que Java puisse l'appeler comme un varargs.

Je pense personnellement que cela devrait être considéré comme un bug du compilateur Scala.

1

Voir la answer to this question:

Vous pouvez utiliser le @annotation.varargs pour instruire scala de générer les deux méthodes:

class Foo { 
    @annotation.varargs def bar(args : String*) : Unit = println("Foo.bar with: " + args) 
    def bar(args : Array[String]) : Unit = bar(args.toSeq : _*) 
}