2010-08-12 5 views
5

Je m'intéresse au problème de la conformité d'un type spécifique à un type structurel plus général. Prenons les exemples suivants:Conformité de type de structure généralisée dans 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 
} 

Dans chacun des cas non conformes, un appel à la méthode General peut être résolu en toute sécurité à la méthode correspondante Specific. Un exemple pratique plus intéressant se trouve dans 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) 
} 

Ici, la méthode du client copy ne se conforme pas à la signature dans l'annotation auto-type de versionnable. Notez, cependant, que si le compilateur est autorisé, copy pourrait être invoqué comme il est dans Versionable.incrementVersion. De toute évidence, la signature réelle de la méthode copy du Client est trop spécifique pour être utilisée dans Versionable, car elle porte la connaissance non pertinente que l'on peut éventuellement fournir un paramètre name.

Existe-t-il des moyens de contourner ces limitations? Y a-t-il des raisons pour lesquelles une telle conformité généralisée serait une mauvaise idée?

+0

Un autre exemple pratique: http://stackoverflow.com/questions/4410469/refactoring-copy-functionality –

Répondre

1

Une préoccupation est que lorsque vous lisez ce code:

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

vous ne vous attendez pas le nom du paramètre à être important, car il devrait être dans cet exemple:

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

EDIT: Sur une autre note, en ce qui concerne l'absence de paramètres contravariance pour les méthodes, vous pouvez faire:

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

C'est un bon point. Ce type de conformité généralisée ne devrait probablement pas être la norme par défaut (pour des raisons de performance). Exiger une annotation '@ named' sur le paramètre' version' dans le type structural résoudrait les deux problèmes, je pense. –

Questions connexes