开发者

View bound not compatible with upper type bound?

I have a method that takes a Comparable and returns a Comparable and wraps another method that does the same thing:

def myMethod[T <: Comparable[T]](arg: T): T = otherMethod(arg)
def otherMethod[T <: Comparable[T]](arg: T): T = arg

This compiles, but doesn't allow me to call myMethod with an Int or any other type that requires an implicit conversion to implement Comparable. As I understand it, view bounds are meant to address this type of problem, but using the view bound

def myMethod[T <% Comparable[T]](arg: T): T = otherMethod(arg)

I get the compiler error:

inferred type arguments [T] do not conform to method otherMethod's type parameter bounds [T <: java.lang.Comparable[T]]

So far, the only workaround I've come up with is to use a second type parameter and cast between the two:

def myMethod[T <% Comparable[T], U <: Comparable[U]](arg: T): T =开发者_如何学JAVA
  otherMethod(arg.asInstanceOf[U]).asInstanceOf[T]

This works, but it's ugly. Is there a better way?


Would either of the following work?

  1. Make the T's view bound consistent in both methods,

    def otherMethod[T <% Comparable[T]](arg: T): T = arg
    def myMethod[T <% Comparable[T]](arg: T): T = otherMethod(arg)
    
  2. Introduce a new type parameter U <: Comparable[U] and an implicit conversion from T to U,

    def otherMethod[T <: Comparable[T]](arg: T): T = arg
    def myMethod[U <: Comparable[U], T <% U](arg: T): U = otherMethod(arg)
    

The problem with your version is that T <% Comparable[T] converts T to type Comparable[T], but this does not satisfy the recursive type T <: Comparable[T <: Comparable[T <: ...]] (pseudocode) that otherMethod expects.


Update. To use either otherMethod or myMethod with Scala's Int, you will need to help the type inferencer a little bit,

myMethod(2)                    // Int value types don't implement Comparable
myMethod(2: java.lang.Integer) // Apply implicit conversion (Int => java.lang.Integer)

Update 2. In the comments, you said you're willing to make myMethod a little uglier to improve type inference at the call site. Here's a way,

def myMethod[U <: Comparable[U], T](arg: T)
     (implicit ev1: T => U, ev2: T => Comparable[U]): U = otherMethod(arg)
myMethod(2) // returns java.lang.Integer(2)

The trick is to use two implicit conversions: ev1 actually gets applied, and ev2 is there only to aid type inference. The latter requires Scala to search its implicits for a conversion of type Int => Comparable[U]. In this case, only one such conversion can be found, which fixes U = java.lang.Integer.

By the way, try compiling this code with scalac -Xprint:typer. You'll see that the same implicit, Predef.int2Integer, is used for both ev1 and ev2 parameters.

Side note: it's best to avoid asInstanceOf casts because those defeat the soundness of the Scala type system.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜