Pregunta

Estoy teniendo un pequeño problema la comprensión de la varianza de los métodos cuando se sobrecarga.

Si bien esto funciona perfectamente debido a la covarianza en el tipo de retorno

class Bla 
class Fasel extends Bla 

trait Test[A] {
 def tester(): Bla = new Bla
}

class FooTest[A](a: A) extends Test[A] {
 override def tester(): Fasel = new Fasel                                      
}

éste falla aunque las funciones son en su contravariant tipos de parámetros.

class Bla 
class Fasel extends Bla 

trait Test[A] {
 def tester(a: Fasel): Bla = new Bla                                           
}

class FooTest[A](a: A) extends Test[A] {
 override def tester(a: Bla): Fasel = new Fasel
}

¿Qué consigo mal aquí? Cualquier punteros?

Saludos, raichoo

¿Fue útil?

Solución

Hay dos cosas pasando aquí:

  1. Una función y un método no son la misma cosa
  2. métodos no son polimórficos en los tipos de sus parámetros

Su método es un método tester, no es un Function1 . Puede ser levantado en una función utilizando la sintaxis de subrayado:

val f = (new FooTest[String]).tester _ // Fasel => Bla

Esta función será contra-variante en su tipo de entrada. (Vale la pena diciendo, sin embargo, que las funciones de no puede ser parametrizado y también vale la pena decir que yo tenía que tener una instancia de Foo o FooTest con el fin de obtener un objeto de función para el método tester. Por supuesto, esto sigue desde la primera observación!)

Una función es un objeto, no puede ser anulado como que no tiene sentido. Los métodos pueden ser anulado. Sin embargo, como ya he dicho anteriormente, la primordial no es polimórfico en los tipos de parámetros del método. Así, por ejemplo:

class A {
  def foo(a : Any) = println("A: " + a)
}

class B extends A {
  override def foo(s : String) = println("B " + s) //will not compile!
}

Los dos métodos en el ejemplo anterior son dos métodos independientes:. Envío dinámico sólo funciona en el objetivo método (es decir, el objeto sobre el que está siendo llamado)

En lo anterior, ejemplo, si se quita la declaración override, el código se compilará. Si ejecuta el siguiente:

(new B).foo(1)   //prints A 1
(new B).foo("s") //prints B s

Esto es porque, aunque ambos métodos se llaman foo, son completamente diferentes métodos (es decir, tengo sobrecargado foo, no reemplazado él). Se entiende mejor como es que un método argumentos (incl sus tipos) forman parte de único nombre de ese método . Un método anula otra sólo si tienen exactamente el mismo Nombre .


En esencia usted ha confundido lo que son dos separados y no relacionados- las cosas en su pregunta, que voy a poner abajo para mayor claridad:

  • Las anotaciones de varianza sobre Function1 definir lo que significa para una función a ser un subtipo de otro (y por tanto asignable a una referencia de un tipo dado).
  • Métodos puede ser anulado en subclases y los contornos especificación del lenguaje de reglas para cuando tales primordial tiene lugar.

Otros consejos

Los fragmentos relevantes de la especificación:

Tipos Método

  

A tipo de método se denota internamente como (Ps)U, donde (Ps) es una secuencia de nombres de parámetros y los tipos (p1 :T1,...,pn :Tn) para algunos n≥0 y U es un (valor o método) tipo. Este tipo representa métodos llamados que tienen argumentos con nombre p1, ..., pn de tipos T1,...,Tn y que devuelven un resultado de tipo U.

     tipos

Método no existen como tipos de valores. Si un nombre de método se utiliza como un valor, su tipo se convierte implícitamente a un tipo de función correspondiente (§6.26).

Anulación

  

A miembro M de C clase que partidos se dice M′ miembro (§5.1.3) un no-privada de una clase base de C para anular ese miembro. En este caso la unión del primordial debe miembro M subsume (§3.5.2) la unión de la M′ miembro anular.

Conformidad

  

Si Ti ≡ Ti′ para i = 1, ..., n y U ajusta a U′ luego los ajusta (p1 : T1,...,pn :Tn)U Tipo de método a (p1′ :T1′,...,pn′ :Tn′)U′.

subsume

  

Una declaración o definición en algún tipo compuesto de tipo de clase C subsume otra declaración del mismo nombre en algún tipo compuesto o tipo de clase C′, si una de las siguientes bodegas.

     
      
  • una declaración de valor o definición que define un nombre x con el tipo T subsume un valor o método declaración que define x con el tipo T′, proporcionado T <: T′.
  •   

Puede anular y cambiar el tipo de retorno a un subtipo, pero aceptando al mismo tiempo supertipo para el argumento podría satisfacer el principio de sustitución, que no está permitido (esto es igual que en java) La razón es que también se puede sobrecargar métodos (varios métodos con el mismo nombre, diferentes argumentos cuentan y tipos) y su método se considerered una sobrecarga. Supongo que esto es principalmente una cuestión de compatibilidad JVM y de tener una especificación razonable. La sobrecarga ya se hace la especificación Scala bastante complicado. Simplemente encaminar el método sobreescrito a la sobrecarga de la firma cambiada podría ser lo suficientemente bueno:

class FooTest[A] extends Test[A] {
   override def test(a: Fasel) : Fasel = test(a.asInstanceOf[Bla])
   def test(a: Bla) : Fasel = new Fasel
}

Lo que puede hacer es hacer una contravariant parámetro de tipo, proporcionada en sólo aparece en la posición contravariante (simplificando, aparece como tipo de argumento y no como tipo de resultado), pero es muy diferente:

trait Test[-A] {
  // note the - before A. 
  // You might want to constraint with -A >: Fasel
  def tester(a: A) : Bla = new Bla
}

class FooTest extends Test[Bla] {
  override def tester(a: Bla): Fasel = new Fasel
}

val testOfBla: Test[Bla] = new FooTest
val testOfFasel: Test[Fasel] = testOfBla 
  // you can assign a Test[Bla] to a test[Fasel] because of the -A

Bueno, en el segundo ejemplo de la firma del tester() en Test declara un argumento Fasel pero con la firma de overriden FooTest tester() se declara con un Bla como argumento. Desde Fasel es un subtipo de Bla por sus extends jerarquía de esto es probablemente equivocado.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top