8

Während ich meinen Kopf über another question knackte, stieß ich auf verschiedene Rätsel, die verwandt scheinen. Dies ist einer von ihnen:Darstellungsart kann nicht als Typ Member implementiert werden

trait Sys[S <: Sys[S]] { 
    type Peer <: Sys[Peer] 
} 

trait Fenced { 
    type Peer <: Sys[Peer] 
} 

def makeFence[S <: Sys[S]] = new Fenced { type Peer = S#Peer } 

Wo der Fehler ist wie folgt:

error: overriding type Peer in trait Fenced with bounds >: Nothing <: Sys[this.Peer]; 
type Peer has incompatible type 
     def makeFence[S <: Sys[S]] = new Fenced { type Peer = S#Peer } 
                ^

Warum? (Auch versucht, sich selbst Typ _:S =>-Sys hinzufügen, spielte keine Rolle)


Während Rex Antwort es möglich macht, das Fenced Objekt zu konstruieren, ist es nicht wirklich um die Probleme zu lösen ich mit der Darstellungsart Charakter haben bei Verwendung einer Typprojektion verloren gehen (S#Peer). Ich habe ein anderes Szenario entwickelt, das härtere Bedingungen mit sich bringt. Ich denke, dies ist die Kernfrage ist:

trait Test[S <: Sys[S]] { 
    def make[T <: Sys[T]](): Unit 

    make[S#Peer]() 
} 

error: type arguments [S#Peer] do not conform to method make's type 
     parameter bounds [T <: Sys[T]] 
       make[S#Peer]() 
       ^
+0

Ich denke, dass das grundlegende Problem 'Merkmal A [B <: Sys [B]]' (das ist in Ordnung) gegen 'Merkmal A {Typ B <: Sys [B]}' (das scheint der Ursprung von alles Ärger). Aber ich muss wirklich mit Typmitgliedern arbeiten, ich kann in meinem Fall keine Typparameter eingeben. –

+0

Was versuchst du zu erreichen? 'S # Peer' ist das' Peer' von 'S', aber' Fenced' will, dass der Peer _its_ 'Peer' und nicht' S's ist, was die Inkompatibilität auf der Oberfläche erzeugt. Ob es logisch inkompatibel ist oder nicht, hängt davon ab, ob Sie Typen als einfache Aliase oder Besitzübersichten betrachten. Scala ist leider nicht ganz konsequent. Willst du nur sagen: "' Fenced' hat einen Typ, der ein 'Sys' ist? –

+0

@RexKerr - Entschuldigung, wenn die Absicht nicht klar war. Die verknüpften Fragen geben den gesamten Zusammenhang wieder. Grundsätzlich, was ich (glaube ich) brauche, ist, zwei verknüpfte Systeme zu definieren, von denen das eine vom anderen bezeichnet wird, so dass ich das äußere System umgehen kann, ohne zusätzliche Informationen außer "S": Sys [S] 'und in der Lage sein, das andere Peer-System vollständig einzubetten, indem nur Typ-Mitglieder des äußeren Systems verwendet werden. Ich stoße hier irgendwie an die Grenzen der Typ-Projektionen. Die Frage versucht dies zu veranschaulichen, indem es sagt, dass es unmöglich scheint, den Peer-Typ innerhalb eines Konsumenten des äußeren Systems wiederzubeleben. –

Antwort

3

Ich bin noch nicht ganz sicher, welche Einschränkungen Sie suchen, aber hier ist eine Möglichkeit: (! Und erfordert)

trait Sys[S <: Sys[S]] { 
    type Peer <: Sys[Peer] 
} 

trait Fenced { 
    type MySys <: Sys[MySys] 
    type Peer = MySys#Peer 
} 

def makeFence[S <: Sys[S]] = new Fenced{ type MySys = S } 

Dies gibt Ihnen Zugang zu sowohl Peer als auch dem ursprünglichen äußeren Typ innerhalb Fenced. Ich bin nicht sicher, ob Fenced dies tun kann, oder ob es über äußere Typen abstrahieren muss.

+0

Sehr interessanter Ansatz, Moving-Typ-Parameter in Typ Mitglied. Ja, es gibt kein Problem, beide Typen in 'Fenced' zu haben. Ich muss das bis zu allen Konsequenzen durchspielen, aber das ist zumindest ein neuer Gedanke für mich, danke! –

+0

Dies funktioniert nur mit einer invarianten 'S' auf' Sys', weil die Bedingung 'Peer <: Sys [Peer] 'für den' Peer' Typ member in 'Fenced' entfällt. –

+0

Das soll nicht heißen, dass es keine gültige Problemumgehung ist, aber im Allgemeinen, wenn Sie ein 'val f = makeFence [X]' mit diesem Ansatz haben, wird es nicht der Fall sein, dass 'f.Peer <: Sys [f .Peer] '(außer wenn' X' natürlich einen konkreten 'Peer' hat, aber ich bin mir nicht sicher, wie ich das als Einschränkung formulieren soll). –

3

Können Sie Sys 's Typ Parameter kovariant machen? Zum Beispiel diese kompiliert:

trait Sys[+S <: Sys[S]] { type Peer <: Sys[Peer] } 
trait Fenced { type Peer <: Sys[Peer] } 

def makeFence[S <: Sys[S]] = new Fenced { type Peer = S#Peer } 

Wenn wir nun die folgende (in einem Objekt gewickelt nur für REPL copy-paste Bequemlichkeit):

object Example { 
    case class SysX(i: Int) extends Sys[SysX] { type Peer = SysY } 
    case class SysY(j: Int) extends Sys[SysY] { type Peer = SysX } 
} 

import Example._ 

Es funktioniert, wie ich erwarten würde:

scala> val fenceX = makeFence[SysX] 
fenceX: java.lang.Object with Fenced{type Peer = Example.SysX#Peer} = ... 

scala> val y: fenceX.Peer = SysY(1) 
y: fenceX.Peer = SysY(1) 

scala> val y: fenceX.Peer = SysX(1) 
<console>:15: error: type mismatch; 
found : Example.SysX 
required: fenceX.Peer 
     val y: fenceX.Peer = SysX(1) 

Welche (glaube ich) ist was du willst?

+0

Sorry Travis, aber 'S' muss invariant bleiben :-( –

+0

@Travis Hi Travis. Ich verstehe nicht ganz, warum die Frage nicht funktioniert, aber ich versuche zu lernen. Können Sie bitte erklären, warum es funktioniert, wenn es Variante und funktioniert nicht, wenn seine Invariante? – Jatin

Verwandte Themen