2010-08-12 7 views
5

Me interesa el problema de conformar un tipo específico a un tipo estructural más general. Consideremos los siguientes ejemplos:Conformidad de tipo estructural generalizada en Scala

trait Sup 

trait Sub extends Sup 

type General = { 
    def contra(o: Sub): Unit 
    def co(): Sup 
    def defaults(age: Int): Unit 
    def defaults2(age: Int): Unit 
    def defaults3(first: String): Unit 
} 

trait Specific { 
    def contra(o: Sup): Unit // doesn't conform 
    def co(): Sub // conforms 
    def defaults(age: Int, name: String = ""): Unit // doesn't conform 
    def defaults2(name: String = "", age: Int = 0): Unit // doesn't conform 
    def defaults3(first: String = "", last: String = ""): Unit // doesn't conform 
} 

En cada uno de los casos no conformes, una llamada al método en General de forma segura se puede resolver con el método correspondiente en Specific. Un ejemplo práctico más interesante se puede encontrar en this question:

trait Versionable[T] { 
    self: { def copy(version: Int): T } => 
    val version = 0 
    def incrementVersion = copy(version = version + 1) 
} 

case class Customer(name: String, override val version: Int) 
     extends Versionable[Customer] { 
    def changeName(newName: String) = copy(name = newName) 
} 

Aquí, el método del Cliente copy no se ajusta a la firma en el tipo de auto anotación de versionable. Sin embargo, tenga en cuenta que, si el compilador lo permite, puede invocarse copy tal como está en Versionable.incrementVersion. Claramente, la firma real del método copy del Cliente es demasiado específica para su uso en Versionable, ya que tiene el conocimiento irrelevante de que uno puede suministrar opcionalmente un parámetro name.

¿Hay formas de evitar estas limitaciones? ¿Hay razones por las cuales esa conformidad generalizada sería una mala idea?

+0

Otro ejemplo práctico: http://stackoverflow.com/questions/4410469/refactoring-copy-functionality –

Respuesta

1

Una preocupación es que cuando lea este código:

self: { def copy(version: Int): T } 

usted no espera el nombre del parámetro a ser significativo, ya que tendría que ser en este ejemplo:

case class Robot(number: Int, override val version: Int) 
    extends Versionable[Robot] 

EDITAR: por otro lado, en cuanto a la falta de contravarianza parámetro para los métodos, puede hacerlo:

type General = { val contra: (Sub => Unit) } 
class B { val contra = ((o:Sup) => println(o)) } 
var b:General = new B 
+0

Ese es un buen punto. Este tipo de conformidad generalizada probablemente no sea el predeterminado de todos modos (por razones de rendimiento). Requerir una anotación '@ named' en el parámetro' version' en el tipo estructural resolvería ambos problemas, creo. –

Cuestiones relacionadas