Scala, cannot implement a universal Java method

I would like to implement a java method that uses generics in scala (2.9.2). But I fail ...

Java Interface Method:

public <T extends Number> void setAttribute(Key<T> key, Number value); 

Scala who wants to implement this 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) } 

The key is as follows:

 public class Key<T> 

But this does not 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 understand what the problem is. Any suggestions / ideas?

Greez GarfieldKlon

+7
source share
3 answers

It seems like the compiler is not happy with your call to setAttributeLocal . setAttributeLocal requires Key[Number] , but you provide Key[_ <: T] . In Java-Land, this means that you are trying to pass Key<? extends Number> Key<? extends Number> off as Key<Number> .

It is assumed that setAttributeLocal accepts Key<? extends Number> Key<? extends Number> or Key[_ <: Number] , depending on whether it is Java or Scala -defined.

+4
source

Something here looks a little bit.

You tried:

 def setAttribute[T <: Number](key: Key[T], value: T) = setAttributeLocal(key, value) 

It seems weird / bad to keep type T for the key, but not use it for the value. I guess where you get an invariant error. You are trying to determine a value of type Number for a key of type T , and the compiler is not sure if he can pass Number for T (as long as he knows that he can pass T for Number ).

Can I see more code?

+1
source

As @jsuereth already pointed out, there is a mismatch between the setAttribute and setAttributeLocal , namely that the former accepts Key[T <: Number] , but captures the value that comes with the key to exactly be a Number , while the latter is more flexible and allows you to use the key and the value T <: Number . It looks rather strange, and you can reconsider this decision. This also leads to the problem explained by @Ben Schulz.

In any case, the compiler (2.9.1) is satisfied with the following setting:

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. */ } } 
+1
source

All Articles