When trying to compile the following code with Scala 2.8.1/JavaFx 2.0 beta
new KeyValue(circle.translateYProperty, random() * height)
I get the following error:
[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
Whereas this line gets compiled just fine:
new KeyValue(circle.translateXProperty.asInstanceOf[WritableValue[Any]], random() * width)
I checked the KeyValue constructor and it has the following signature:
public <T> KeyValue(javafx.beans.value.WritableValue<T> tWritableValue, T t) { /* compiled code */ }
circle.translateXProperty returns DoubleProperty which implements the following interface:
public interface WritableNumberValue extends javafx.beans.value.WritableValue<java.lang.Number>
What would be more elegant solution than casting to make it compile?
-- Revised answer, based on Exception and Blaisorblade's comments --
You've hit a limitation of Scala's application of implicits, rather than (just) a Scala-Java interop problem. Here's a simplified example,
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
The first call to f
works because the common supertype of java.lang.Double
and java.lang.Number
is java.lang.Number
, so that is the type inferred for T
.
The second call to f
works because we've explicitly told the compiler that T==java.lang.Number
. When the compiler finds the second argument, 0 : Int
, doesn't match the expected type java.lang.Number
, it searches for an implicit conversion from Int
to Number
. The compiler finds Predef.int2Integer
and applies it. All is well.
The third call to f
doesn't work, because the first parameter constrains T == Number
, and the second argument says T >: Int
(that is, T
is a supertype of Int
). The common supertype of Int
and Number
is Any
, but that won't work because Foo[T]
is not covariant in T
(in other words, we can't cast a Foo[Number]
to a Foo[Any]
). That's the gist of the compiler's error message. Note that the compiler doesn't know how to apply an implicit conversion, because it doesn't know a specific type of T
to convert to.
One strange thing about the JavaFX code that you posted is that the KeyValue
class is not generic, but is has a generic constructor. Interestingly, this is not possible in Scala, so there's no way (as far as I can tell), to explicitly constrain the parameter T
from Scala code. If the entire KeyValue
class were generic, you'd also be able to write
new KeyValue[Number](circle.translateYProperty, random() * height)
which would be equivalent to the code that Exception posted, since the compiler would infer the double2Double
conversion.
I had the same problem a few days ago. After trying different things i ended up with that.
new KeyValue(circle.translateYProperty, double2Double(random() * height))
(see Blaisorblade comments for explanation)
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