2011-07-31 24 views
13

Considere el siguiente código Scala:¿Por qué Scala no infiere completamente los parámetros de tipo cuando los parámetros de tipo están anidados?

abstract class A 
abstract class B[T <: A] 
class ConcreteA extends A 
class ConcreteB extends B[ConcreteA] 

class Example[U <: B[T], T <: A](resolver: U) 
object Test { 
    new Example(new ConcreteB) 
} 

La última línea new Example(new ConcreteB) falla al compilar con el siguiente error:

error: inferred type arguments [ConcreteB,Nothing] do not conform to class Example's type parameter bounds [U <: B[T],T <: A]

Pero ConcreteB tiene todos los datos necesarios para resolver tanto T y T. ¿Que me estoy perdiendo aqui?

+0

posible duplicado de [Type infered to Nothing in Scala] (http://stackoverflow.com/questions/6888136/type-infered-to-nothing-in-scala) –

+1

Es similar, pero la respuesta aceptada a eso la pregunta no se aplica en este caso. –

Respuesta

10

Kipton se acercó con su solución de alto nivel. Desafortunadamente tropezó con lo que parece ser un error en Scala < 2.9.1.RC1. Los siguientes trabajos como se esperaba con 2.9.1.RC1 y el tronco,

Welcome to Scala version 2.9.1.RC1 (Java HotSpot(TM) Server VM, Java 1.7.0). 
Type in expressions to have them evaluated. 
Type :help for more information. 

scala> abstract class A 
defined class A 

scala> abstract class B[T <: A] 
defined class B 

scala> class ConcreteA extends A 
defined class ConcreteA 

scala> class ConcreteB[T <: A] extends B[T] 
defined class ConcreteB 

scala> class Example[T <: A, U[X <: A] <: B[X]](resolver: U[T]) 
defined class Example 

scala> new Example(new ConcreteB[ConcreteA]) 
res0: Example[ConcreteA,ConcreteB] = [email protected] 
+0

Está cerca, pero luego ConcreteB no es realmente concreto. ¿Funciona esto para usted sin tener que parametrizar explícitamente ConcreteB? –

+0

No puedo obtener inferencia para trabajar sin la parametrización explícita de 'ConcreteB' (pero el enfoque de tipo de miembro que mencioné al principio funciona bien). –

+0

Gracias, supongo que esto es lo más cercano que se puede llegar a este punto. –

10

(Véase también dos preguntas relacionadas: Scala fails to infer the right type arguments y Type infered to Nothing in Scala)

se ve como una limitación de la inferencia de tipos de Scala, que intencionadamente no se spec'ed. Como solución alternativa, puede obtener la inferencia haciendo T un miembro de tipo de B en lugar de los parámetros,

abstract class A 
abstract class B { type T <: A } 
class ConcreteA extends A 
class ConcreteB extends B { type T = ConcreteA } 
class Example[U <: B](resolver: U) 
object Test { 
    new Example(new ConcreteB) 
} 

Al usar miembros de tipo, es útil saber que pueden estar recubiertos según los parámetros de tipo utilizando el refinamiento, como en la respuesta de Miles Sabin a: Why is this cyclic reference with a type projection illegal?

En la respuesta de Jean-Philippe Pellet al a related question, la inferencia tipo fue ayudada haciendo que el parámetro tipo sea más alto. Si introduce un parámetro de tipo adicional en ConcreteB, a continuación, escriba la inferencia puede trabajar,

abstract class A 
abstract class B[T <: A] 
class ConcreteA extends A 
class ConcreteB[T <: A] extends B[T] 
class Example[T <: A, U[T0 <: A] <: B[T0]](resolver: U[T]) 
object Test { 
    new Example(new ConcreteB[ConcreteA]) 
} 

Scala 2.9 da el mensaje de error misteriosa abajo, pero Miles Sabin señala que es un error que se fija por 2,9. 1

<console>:15: error: kinds of the type arguments (ConcreteA,ConcreteB[T0]) do not conform to the expected kinds of the type parameters (type T,type U) in class Example. 
ConcreteB[T0]'s type parameters do not match type U's expected parameters: class ConcreteB has one type parameter, but type U has one 
     new Example(new ConcreteB[ConcreteA]) 
      ^
+1

Consulte la discusión continuada sobre la respuesta de Miles a continuación. –

+0

La respuesta de Miles ahora está arriba ya que se ha convertido en la respuesta aceptada. – ArtB

2

he compuesto a document of type inference workarounds en GitHub para mi propio aprendizaje.

Unas pocas reglas simples que encuentro útiles son:

  • parámetros de tipo de parámetros de tipo no se pueden deducir: tipo Scala inferencia sólo ve tipos especificados en la lista parámetro (que no debe confundirse con lista de parámetros de tipo).

  • parámetros anteriores no se utilizan para inferir parámetros futuros: información Tipo sólo fluye a través de parámetros listas, no parámetros.


Sin embargo, en este ejemplo particular miembros de tipo son el camino a seguir (gracias @Kipton Barros!)

Cuestiones relacionadas