8

Mentre mi si spezza la testa su another question, mi sono imbattuto in enigmi diversi che sembrano correlati. Questo è uno di loro:Impossibile implementare il tipo di rappresentazione come membro del tipo

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 } 

dove l'errore è la seguente:

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 } 
                ^

Perché? (Cercato anche di aggiungere auto-tipo _:S =>-Sys, non importa)


Mentre la risposta di Rex permette di costruire l'oggetto Fenced, in realtà non risolve i problemi che ho con il carattere tipo di rappresentazione perdersi quando si utilizza un tipo di proiezione (S#Peer). Ho trovato un altro scenario che pone vincoli più difficili; Credo che questo sia il problema centrale:

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

Sto pensando che il problema fondamentale sia 'tratto A [B <: Sys [B]]' (che va bene) rispetto a 'tratto A {tipo B <: Sys [B]}' (che sembra l'origine di tutti i problemi). Ma ho davvero bisogno di lavorare con i membri dei tipi, non posso introdurre i parametri di tipo nel mio caso. –

+0

Cosa stai cercando di realizzare? 'S # Peer' è quel' Peer' di 'S', ma' Fenced' vuole che il peer sia _its_ 'Peer' non' S', che genera l'incompatibilità (a livello di superficie). Indipendentemente dal fatto che sia logicamente incompatibile, credo dipenda dal fatto che si vedano i tipi come semplici alias o dichiarazioni di proprietà. Scala non è del tutto coerente su questo, sfortunatamente. Stai semplicemente cercando di dire "' Recintato "ha un tipo che è un" Sys' "? –

+0

@RexKerr - scusa se l'intenzione non era chiara. Le domande collegate danno l'intero contesto. Fondamentalmente, quello di cui (penso di) ho bisogno è di definire due sistemi collegati, uno a cui si fa riferimento l'altro, in un modo che mi permetta di aggirare il sistema esterno, senza ulteriori informazioni oltre a 'S <: Sys [S] 'ed essere in grado di incorporare completamente l'altro sistema peer, usando solo i membri di tipo del sistema esterno. In questo caso, sto arrivando a superare i limiti delle proiezioni di tipo. La domanda cerca di illustrare ciò dicendo che sembra impossibile resuscitare il tipo di peer all'interno di un consumatore del sistema esterno. –

risposta

3

io ancora non sono del tutto sicuro che cosa vincoli che stai cercando, ma qui è una possibilità: (! E richiede)

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 } 

questo ti dà accesso a entrambi Peer e il tipo esterno originale all'interno di Fenced. Non sono sicuro che lo Fenced possa farlo o se debba astrarre i tipi esterni.

+0

Approccio molto interessante, spostamento del parametro del tipo in membro del tipo. Sì, non ci sono problemi con entrambi i tipi in 'Fenced'. Devo interpretare tutto questo per tutte le conseguenze, ma almeno questo è un nuovo pensiero per me, grazie! –

+0

Funziona solo con un 'S' invariante su' Sys' perché rilascia il vincolo 'Peer <: Sys [Peer]' per il membro di tipo 'Peer' in' Fenced'. –

+0

Il che non vuol dire che non sia una soluzione valida, ma in generale se si ha un 'val f = makeFence [X]' con questo approccio, non sarà il caso che 'f.Peer <: Sys [f .Peer] '(tranne quando' X' ha un 'Peer 'concreto, ovviamente, ma non sono sicuro di come esprimerlo come un vincolo). –

3

Puoi fare il parametro di tipo Sys covariant? Ad esempio, questo compila:

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 } 

Ora, se abbiamo la seguente (avvolto in un oggetto solo per REPL copia-incolla comodità):

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._ 

Funziona come mi aspetto:

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) 

Quale (penso) è quello che vuoi?

+0

Scusate Travis, ma 'S' deve rimanere invariante :-( –

+0

@Travis Ciao Travis. Non capisco completamente perché la domanda non funziona, ma sto cercando di imparare. Puoi spiegare perché funziona? variante e non funziona se è invariante? – Jatin

Problemi correlati