I am walking around a problem, and I found a new strange problem with type projections and abstract types. Say I have a system which spawns transactions, and there is a peer system to which I want to bridge. The following looks good to me:
trait Txn[S <: Sys[S]] {
def peer: S#Peer#Tx
def newID(): S#ID
def newVar[A](id: S#ID, init: A): S#Var[A]
}
trait Sys[S <: Sys[S]] {
type Tx <: Txn[S]
type Peer <: Sys[Peer] // parallel system
type Var[A]
type ID
}
And I can use the direct system:
def directWorks[S <: Sys[S]](implicit tx: S#Tx): Unit = {
val id = tx.newID()
val v = tx.newVar(id, 0)
}
But somehow the peer
method of the transaction is flawed, as the following shows:
def indirectDoesnt[S <: Sys[S]](implicit tx: S#Tx): Unit = {
val p = tx.peer
val id = p.newID()
val v = p.newVar(id, 0) // what the **** - id is not compatible??
}
error: type mismatch;
found : id.type (with underlying type S#Peer#ID)
required: _30129.Peer#ID where val _30129: S
val v = p.newVar(id, 0)
^
I wanted to be clever and work around it:
def clever[S <: Sys[S]](implicit tx: S#Tx): Unit = {
def directWorks[S <: Sys[S]](implicit tx: S#Tx): Unit = {
val id = tx.newID()
val v = tx.newVar(id, 0)
}
directWorks(tx.peer)
}
...but that fails, too, giving more clues about what's wrong:
error: inferred type arguments [S#Peer] do not conform to method
directWorks's type parameter bounds [S <: Sys[S]]
directWorks(tx.peer)
^
It all suggests that either def peer: S#Peer#Tx
introduces a problem, or (more likely?) that type Peer <: Sys[Peer]
is problematic when not used as type parameter but type member.