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.
Now here is an almost acceptable solution. It is based on the idea to "fix" the representation types in
Sys
; in a concrete systemS
, we will always haveS#S#Tx == S#Tx
etc. My understanding of this solution is that it moves the responsibility for variance from the use site to the system itself.Since this involves some ceremony, I'd be still very grateful about additional answers regarding removal or reduction of this ceremony; as well as explanations regarding why this works and omitting the call to
fix
does not work.Now two example systems. First:
Second:
And verfication on the use site: