I'd like to implement a java method that uses generics in scala (2.9.2). But I'm failing...
Java interface method:
public <T extends Number> void setAttribute(Key<T> key, Number value);
Scala code that want to implement that method:
def setAttribute[T <: Number](key: Key[T], value: Number) = {
setAttributeLocal(key, value) }
private def setAttributeLocal[T](key: Key[T], value: T) = {
val stringValue = ConvertUtils.convert(value, classOf[String]).asInstanceOf[String]
session = session + (key.getValue() -> stringValue)
}
Key looks like:
public class Key<T>
But this doesn't compile.
[error] found : mypackage.Key[T]
[error] required: mypackage.Key[java.lang.Number]
[error] Note: T <: java.lang.Number, but Java-defined class Key is invariant in type T.
[error] You may wish to investigate a wildcard type such as `_ <: java.lang.Number`. (SLS 3.2.10)
[error] setAttributeLocal(key, value)
I can't figure out what's the problem. Any suggestions/idea?
greez GarfieldKlon
It appears the compiler is unhappy with your call to setAttributeLocal
. setAttributeLocal
requires a Key[Number]
, but you are providing a Key[_ <: T]
. In Java-Land this means you're trying to pass a Key<? extends Number>
Key<? extends Number>
off as a Key<Number>
.
The suggestion is to have setAttributeLocal
accept Key<? extends Number>
Key<? extends Number>
or Key[_ <: Number]
, depending on whether it is Java- or Scala-defined.
Something looks a bit off here.
Have you tried:
def setAttribute[T <: Number](key: Key[T], value: T) =
setAttributeLocal(key, value)
It seems strange/bad to preserve the type T for the key, but not use it on the value. My guess is that's where you're getting an invariant error. You're trying to assing the value of type Number
to a key of type T
and the compiler isn't sure if it can't pass Number
for T
(while it knows it can pass T
for Number
).
Can we see more code?
As @jsuereth already pointed out, there is a discrepancy between the signatures of setAttribute
and setAttributeLocal
, namely, that the former accepts a Key[T <: Number]
but fixes the value that goes with the key to exactly be a Number
, whereas the latter is more flexible and allows key and value to be T <: Number
. This looks rather odd and you might want to reconsider that decision. It also leads to the problem explained by @Ben Schulz.
In any case, the compiler (2.9.1) is happy with the following setup:
MyI.java
:
public interface MyI {
public <T extends Number> void setAttribute(Key<T> key, Number value);
}
Key.java
:
public interface Key<T> {
}
Test.scala
:
object Test extends App {
def setAttribute[T <: Number](key: Key[T], value: Number) = {
setAttributeLocal(key, value) }
private def setAttributeLocal[T](key: Key[T], value: Number) = {
/* Notice that value is now also of type Number. */
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.