简体   繁体   中英

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 =
  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.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM