2011-08-05 1 views
4

paramétrisé Lorsque vous essayez de compiler le code suivant avec Scala 2.8.1/JavaFX 2.0 betaerreur de compilation Scala avec le constructeur et l'interface Java paramétrées

new KeyValue(circle.translateYProperty, random() * height) 

Je reçois l'erreur suivante:

[error] found : javafx.beans.property.DoubleProperty 
[error] required: javafx.beans.value.WritableValue[Any] 
[error]    new KeyValue(circle.translateYProperty, random() * height) 
[error]        ^
[error] one error found 

Alors que cette ligne est compilée très bien:

new KeyValue(circle.translateXProperty.asInstanceOf[WritableValue[Any]], random() * width) 

J'ai vérifié le constructeur KeyValue et il a la signature suivante:

public <T> KeyValue(javafx.beans.value.WritableValue<T> tWritableValue, T t) { /* compiled code */ } 

circle.translateXProperty retours DoubleProperty qui implémente l'interface suivante:

public interface WritableNumberValue extends javafx.beans.value.WritableValue<java.lang.Number> 

Quelle serait la solution plus élégante que la coulée de le faire compiler?

+0

Avez-vous essayé spécifiant explicitement le type? 'new KeyValue [Any] (cercle ...)' – agilesteel

+0

Oui, j'ai essayé mais ça dit _KeyValue ne prend pas de type paramètres_ (la classe _KeyValue_ n'est pas paramétrée, seul le constructeur est) – Stas

+1

Aussi je ne pense pas que ça changerait quoi que ce soit - à partir du message d'erreur, vous pouvez voir que le compilé a déjà déduit 'Any' comme étant la limite de' T'. –

Répondre

5

-réponse révisée, fondée sur l'exception et les commentaires de Blaisorblade -

Vous avez frappé une limitation de l'application de Scala de implicits, plutôt que (juste) un problème Interop Scala Java. Voici un exemple simplifié,

class Foo[T] 
def f[T](x: Foo[T], y: T): T = y 

f(new Foo[Number], new java.lang.Double(0)) // OK; infers T==Number 
f[Number](new Foo[Number], 0)    // OK; uses implicit int2Integer(0) 
// f(new Foo[Number], 0)     // error 
  • Le premier appel à f fonctionne parce que la commune de supertype java.lang.Double et java.lang.Number est java.lang.Number, de sorte que le type est déduit pour T. Le deuxième appel à f fonctionne parce que nous avons explicitement dit au compilateur que T==java.lang.Number. Lorsque le compilateur trouve le deuxième argument, 0 : Int, ne correspond pas au type attendu java.lang.Number, il recherche une conversion implicite de Int à Number. Le compilateur trouve Predef.int2Integer et l'applique. Tout est bien.

  • Le troisième appel à f ne fonctionne pas, car le premier paramètre contraint T == Number, et le second argument dit T >: Int (c'est T est un super-type de Int). Le supertype commun de Int et Number est Any, mais cela ne fonctionnera pas car Foo[T] n'est pas covariant dans T (en d'autres termes, nous ne pouvons pas transformer un Foo[Number] en Foo[Any]). C'est l'essentiel du message d'erreur du compilateur. Notez que le compilateur ne sait pas comment appliquer une conversion implicite, car il ne connaît pas un type spécifique de T à convertir en.

Une chose étrange au sujet du code JavaFX que vous avez publié est que le KeyValue class n'est pas générique, mais il est a un constructeur générique. Fait intéressant, c'est pas possible dans Scala, donc il n'y a aucun moyen (autant que je sache), de contraindre explicitement le paramètre T du code Scala.Si l'ensemble de la classe KeyValue était générique, vous seriez aussi capable d'écrire

new KeyValue[Number](circle.translateYProperty, random() * height) 

qui serait équivalent au code affiché exception, puisque le compilateur déduire la conversion double2Double.

+0

Merci, ça me semble raisonnable! – Stas

+1

J'ai réécrit ma réponse puisque mon original était trompeur. –

3

J'ai eu le même problème il y a quelques jours. Après avoir essayé différentes choses, je me suis retrouvé avec ça.

new KeyValue(circle.translateYProperty, double2Double(random() * height)) 

(voir commentaires Blaisorblade pour l'explication)

+0

Je suis tenté de remettre en question la solution, mais pas l'explication. Je crois que le problème est probablement lié à l'inférence de type - le paramètre de type T est déduit Any (comme indiqué par les messages d'erreur), il n'y a donc pas besoin d'appliquer une conversion implicite, donc la conversion n'est pas appliquée. – Blaisorblade

+0

C'est un bon point et je dois souligner que c'est juste une supposition. J'essaie toujours de comprendre ce qui cause le problème. Mais je me demande pourquoi cela fonctionne si vous lui donnez un java.lang.Double si cela a quelque chose à voir avec T étant déduit comme Any – lucidd

+2

Un problème est que le supertype commun pour java.lang.Number et scala.Double est Any - if vous changez ce dernier en java.lang.Double, le supertype commun est java.lang.Number. Je ne sais pas pourquoi Any est déduit, sauf si WritableValue est considéré comme covariant (mais je pense que ce n'est pas le cas, étant donné les erreurs). – Blaisorblade

Questions connexes