2012-11-11 4 views
5

Ich bin neu bei Scala und weiß nicht, warum ich eine (nicht intuitive für mich) Typumwandlung in Bezug auf pfadabhängige Typen im folgenden Code machen muss. (Ich mag nicht Getter, Setter noch nulls, sie sind hier, um getrennte Vorgänge und die Fehlerquelle disambiguate)Wie vermeidet man schreckliche Typumwandlungen mit pfadabhängigen Typen?

// Module A public API 
class ModA { 
    trait A 
} 

// Module B public API that depends on types defined in Module A 
class ModB(val modA: ModA) { 
    trait B { 
    def getA: modA.A; 
    def setA(anA: modA.A); 
    } 
} 

// One implementation of Module A 
class ModAImpl extends ModA { 
    class AImpl extends A 
} 

// One implementation of Module B 
class ModBImpl(mod: ModA) extends ModB(mod) { 
    class BImpl extends B { 
    private[this] var privA: modA.A = _; 
    override def getA = privA; 
    override def setA(anA: modA.A) = privA = anA; 
    } 
} 

object Main { 
    def main(args: Array[String]): Unit = { 
    // wiring the modules 
    val modAImpl = new ModAImpl; 
    val modBImpl = new ModBImpl(modAImpl); 

    // wiring objects 
    val a = new modAImpl.AImpl; 
    val b = new modBImpl.BImpl; 
    b.setA(a); //don't compile and complain: type mismatch; found: modAImpl.A required: modBImpl.modA.A 

    //i have to do this horrible and coutnerintuitive cast to workaround it 
    b.setA(a.asInstanceOf[modBImpl.modA.A]); 

    var someA: modAImpl.A = null; 
    someA = b.getA; // don't compile with same reason 
    someA = b.getA.asInstanceOf[modAImpl.A]; // horrible cast to workaround 

    println(a == b.getA); // however this prints true 
    println(a eq b.getA); // this prints true too 
    } 
} 

Ich habe über Singleton Typen lesen Sie den Compiler zu informieren, wenn zwei Typen gleich sind, aber ich weiß nicht, wie ich das hier anwenden soll. Vielen Dank im Voraus.

Antwort

5

Sie können einen Typ-Parameter auf den ModB Typen halten:

class ModA { trait A } 

class ModB[AA](val modA: ModA { type A = AA }) { 
    trait B { 
    def getA: AA 
    def setA(anA: AA) 
    } 
} 

class ModAImpl extends ModA { class AImpl extends A } 

class ModBImpl[AA](
    mod: ModA { type A = AA }) extends ModB(mod) { 
    class BImpl extends B { 
    private[this] var privA: AA = _ 
    override def getA = privA 
    override def setA(anA: AA) = privA = anA 
    } 
} 

Und die Typinferenz alle ausarbeitet wie gewünscht:

scala> val modAImpl = new ModAImpl 
modAImpl: ModAImpl = [email protected] 

scala> val modBImpl = new ModBImpl(modAImpl) 
modBImpl: ModBImpl[modAImpl.A] = [email protected] 

scala> val a = new modAImpl.AImpl 
a: modAImpl.AImpl = [email protected] 

scala> val b = new modBImpl.BImpl 
b: modBImpl.BImpl = [email protected] 

scala> b.setA(a) 
+0

Sehr Dank für Travis zu beantworten, aber Ihre Lösung funktioniert nur innerhalb Der Klassenbereich innerhalb eines Methodenbereichs (wie im Beispiel, das ich ursprünglich angegeben hatte) funktioniert nicht. Die Zeile: 'val modBImpl = new ModBImpl (modAImpl);' die zuvor kompiliert wurden, klagt jetzt mit: type mismatch; gefunden: ModAImpl benötigt: M forSome {Typ M <: ModA {Typ A = this.A}} und die Zeile 'b.set (a)' klagt jetzt mit: type mismatch; found: modAImpl.A erforderlich: this.A –

+0

In diesem Fall können Sie den Typparameter explizit angeben ('val modBImpl = new ModBImpl [modAImpl.A] (modAImpl)'). Was nicht befriedigend ist, aber es funktioniert, und es ist besser als Casting. –

+0

Sorry Travis, aber die Codezeile, die du gerade geschrieben hast, kompiliert nicht. Trotzdem, bitte gehen Sie davon aus, dass das Merkmal ModA viele Mitglieder hat, nicht nur A. Ich brauche alle Mitglieder von ModA, die auf ModB verfügbar sind. –

Verwandte Themen