2010-08-12 20 views
5

Sono interessato al problema di conformare un tipo specifico a un tipo strutturale più generale. Considerare i seguenti esempi:Conformità di tipo strutturale generalizzata in 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 
} 

In ciascuno dei casi non conformi, una chiamata al metodo General può tranquillamente essere risolto al metodo corrispondente Specific. Un esempio pratico più interessante può essere trovato in 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) 
} 

Qui, il metodo del Cliente copy non è conforme alla firma in auto-tipo di annotazione di versionable. Si noti, tuttavia, che se il compilatore è consentito, copy può essere richiamato così come è in Versionable.incrementVersion. Chiaramente, la firma effettiva del metodo copy del cliente è troppo specifica per l'uso in Versionable, poiché contiene la conoscenza irrilevante che si può facoltativamente fornire un parametro name.

Esistono modi per aggirare queste limitazioni? Ci sono ragioni per cui una simile generalizzazione sarebbe una cattiva idea?

+0

Un altro esempio pratico: http://stackoverflow.com/questions/4410469/refactoring-copy-functionality –

risposta

1

Una preoccupazione è che quando si legge questo codice:

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

che non ti aspetti il ​​nome del parametro per essere significativo, in quanto avrebbe dovuto essere in questo esempio:

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

EDIT: in un'altra nota, per quanto riguarda la mancanza di parametri controvarianza per i metodi, si può fare:

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

Questo è un buon punto. Questo tipo di conformità generalizzata dovrebbe probabilmente non essere il default in ogni caso (per ragioni di prestazioni). Richiedere un'annotazione '@ named' sul parametro' version' nel tipo strutturale risolverebbe entrambi i problemi, credo. –

Problemi correlati