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?
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)
Introduce a new type parameter
U <: Comparable[U]
and an implicit conversion fromT
toU
,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.
精彩评论