While cracking my head over another question, I came across different riddles which seem related. This is one of them:
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 }
Where the error is as follows:
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 }
^
Why? (also tried to add self-type _:S =>
to Sys
, didn't matter)
While Rex's answer makes it possible to construct the Fenced
object, it does not really solve the issues I have with the representation type character getting lost when using a type projection (S#Peer
). I have come up with another scenario which poses harder constraints; I think this is the core issue:
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]()
^
trait A[B <: Sys[B]]
(which is fine) versustrait A { type B <: Sys[B] }
(which seems the origin of all trouble). But I really need to work with type members, I cannot introduce type parameters in my case. – CoalyS#Peer
is thatPeer
fromS
, butFenced
wants the peer to be itsPeer
notS
's, which generates the (surface-level) incompatibility. Whether or not it is logically incompatible I guess depends on whether you view types as simple aliases or statements of ownership. Scala is not entirely consistent on this, unfortunately. Are you simply trying to say "Fenced
has a type that is aSys
"? – AvoidS <: Sys[ S ]
and being able to embed the other peer system fully, using only type members of the outer system. I am kind of hitting the limits of type-projections here. The question tries to illustrate this by saying that it seems impossible to resurrect the peer type within a consumer of the outer system. – Coaly