8

Mientras agrieta mi cabeza sobre another question, me encontré con diferentes acertijos que parecen relacionados. Esta es una de ellas:No se puede implementar el tipo de representación como miembro de 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 } 

Cuando el error es el siguiente:

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

¿Por qué? (También intentó añadir uno mismo tipo _:S => a Sys, no importaba)


Si bien la respuesta de Rex hace que sea posible construir el objeto Fenced, que en realidad no resuelve los problemas que tengo con el personaje tipo de representación perderse al utilizar una proyección de tipo (S#Peer). He llegado a otro escenario que plantea restricciones más difíciles; Creo que esta es la raíz del problema:

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

Estoy pensando que el problema fundamental es 'rasgo A [B <: Sys [B]]' (que está bien) contra 'rasgo A {tipo B <: Sys [B]}' (que parece ser el origen de todos los problemas). Pero realmente necesito trabajar con miembros de tipo, no puedo introducir parámetros de tipo en mi caso. –

+0

¿Qué estás tratando de lograr? 'S # Peer' es ese' Peer' de 'S', pero' Fenced' quiere que el par sea _its_ 'Peer' y no' S''s, lo que genera la incompatibilidad (a nivel de superficie). Si o no es lógicamente incompatible, supongo que depende de si ve los tipos como alias simples o declaraciones de propiedad. Scala no es del todo coherente en esto, desafortunadamente. ¿Estás tratando de decir "' Fenced' tiene un tipo que es 'Sys'"? –

+0

@RexKerr: lo siento si la intención no estaba clara. Las preguntas vinculadas dan el contexto completo. Básicamente, lo que yo (creo que) necesito es definir dos sistemas vinculados, uno referido por el otro, de una manera que me permita pasar alrededor del sistema externo, sin información adicional que no sea 'S <: Sys [S] 'y poder incrustar completamente el otro sistema de pares, usando solo miembros de tipo del sistema externo. Estoy llegando al límite de las proyecciones de tipos aquí. La pregunta trata de ilustrar esto diciendo que parece imposible resucitar el tipo de igual dentro de un consumidor del sistema externo. –

Respuesta

3

todavía no estoy del todo seguro de lo que las limitaciones que estás buscando, pero aquí es una de las posibilidades: (y requiere)

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 } 

Esto le da acceso a ambos Peer y el tipo externo original dentro de Fenced. No estoy seguro de si Fenced puede hacer esto, o si debe abstraerse entre los tipos externos.

+0

Enfoque muy interesante, mover parámetro de tipo en miembro de tipo. Sí, no hay problema para tener ambos tipos en 'Fenced'. Tengo que jugar esto con todas las consecuencias, pero al menos este es un nuevo pensamiento para mí, ¡gracias! –

+0

Esto solo funciona con un 'S' invariante en' Sys' porque deja caer la restricción 'Peer <: Sys [Peer]' para el miembro de tipo 'Peer' en' Fenced'. –

+0

Lo que no quiere decir que no sea una solución válida, pero en general si tiene un 'val f = makeFence [X]' con este enfoque, no será el caso que 'f.Peer <: Sys [f .Peer] '(excepto cuando' X' tiene un 'Peer' concreto, por supuesto, pero no estoy seguro de cómo expresar eso como una restricción). –

3

¿Puede hacer que el parámetro de tipo Sys sea covariante? Por ejemplo, este 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 } 

Ahora bien, si tenemos el siguiente (envuelto en un objeto sólo por conveniencia REPL de copiar y pegar):

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

Funciona como yo esperaría:

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) 

¿Cuál (creo) es lo que quieres?

+0

Lo siento Travis, pero 'S' debe permanecer invariante :-( –

+0

@Travis Hola Travis. No entiendo completamente por qué la pregunta no funciona, pero estoy tratando de aprender. ¿Puede explicar por qué funciona si su co- variante y no funciona si es invariante? – Jatin

Cuestiones relacionadas