¿El límite de vista no es compatible con el límite de tipo superior?

Tengo un método que toma un Comparable y devuelve un Comparable y envuelve otro método que hace lo mismo:

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

Esto se compila, pero no me permite llamar a myMethod con un Int o cualquier otro tipo que requiera una conversión implícita para implementar Comparable. Según tengo entendido, los límites de vista están destinados a abordar este tipo de problema, pero utilizando el límite de vista

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

Me sale el error del compilador:

Los argumentos de tipo inferido [T] no se ajustan a los límites del parámetro de tipo del método otherMethod [T <: java.lang.Comparable [T]]

Hasta ahora, la única solución que he encontrado es usar un segundo parámetro de tipo y lanzar entre los dos:

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

Esto funciona, pero es feo. ¿Existe una forma mejor?

preguntado el 27 de agosto de 11 a las 22:08

1 Respuestas

¿Funcionaría alguno de los siguientes?

  1. Haz el TEl límite de vista es consistente en ambos métodos,

    def otherMethod[T <% Comparable[T]](arg: T): T = arg
    def myMethod[T <% Comparable[T]](arg: T): T = otherMethod(arg)
    
  2. Introducir un nuevo parámetro de tipo U <: Comparable[U] y una conversión implícita de T a U,

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

El problema con tu versión es que T <% Comparable[T] conversos T digitar Comparable[T], pero esto no satisface el tipo recursivo T <: Comparable[T <: Comparable[T <: ...]] (pseudocódigo) ese otherMethod espera.


Noticias. Para usar cualquiera otherMethod or myMethod con Scala's Int, deberá ayudar un poco al inferenciador de tipos,

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

actualización 2. En los comentarios, dijiste que estás dispuesto a hacer myMethod un poco más feo para mejorar la inferencia de tipos en el sitio de la llamada. Aquí hay una manera

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)

El truco consiste en utilizar dos conversiones implícitas: ev1 realmente se aplica, y ev2 ¿Existe solo para ayudar a la inferencia de tipos? Este último requiere que Scala busque sus implícitos para una conversión de tipo Int => Comparable[U]. En este caso, solo se puede encontrar una conversión de este tipo, que corrige U = java.lang.Integer.

Por cierto, intente compilar este código con scalac -Xprint:typer. Verás que lo mismo implícito, Predef.int2Integer, se usa para ambos ev1 y ev2 parámetros.

Nota al margen: es mejor evitar asInstanceOf lanzamientos porque estos derrotan la solidez del sistema de tipos Scala.

Respondido 28 ago 11, 06:08

1. No, lamentablemente otherMethod está definido en una biblioteca de terceros. 2. ¡Sí! Esto parece funcionar. ¡Gracias! - ethzero

En realidad, hablé demasiado pronto ... la segunda solución se compila, pero todavía no puedo llamarla con un Int. Aquí está el error: "los argumentos de tipo [Int, Int] no se ajustan a los límites del parámetro de tipo de myMethod [U <: java.lang.Comparable [U], T]" - ethzero

¿No es eso también un problema con otherMethod definido en la biblioteca de terceros? Obtengo el mismo error con otherMethod(2). - Kipton Barros

Sí, no puedo llamar a otherMethod directamente con un Int. Eso es en parte de lo que quiero que me encargue el método de envoltura :) - ethzero

Prefiero no tener que especificar java.lang.Integer al llamar a myMethod. Si tiene que haber fealdad, es mejor encapsularla dentro de myMethod. - ethzero

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.