I would like to move a type parameter to a type member.
This is the starting point which works:
trait Sys[S <: Sys[S]] {
type Tx
type Id <: Identifier[S#Tx]
}
trait Identifier[Tx] {
def dispose()(implicit tx: Tx): Unit
}
trait Test[S <: Sys[S]] {
def id: S#Id
def dispose()(implicit tx: S#Tx) {
id.dispose()
}
}
What annoys me is that I'm carrying around a type parameter [S <: Sys[S]]
throughout my entire libraries. So what I was thinking is this:
trait Sys {
type S = this.type // ?
type Tx
type Id <: Identifier[S#Tx]
}
trait Identifier[Tx] {
def dispose()(implicit tx: Tx): Unit
}
trait Test[S <: Sys] {
def id: S#Id
def dispose()(implicit tx: S#Tx) {
id.dispose()
}
}
Which fails... S#Tx
and S#Id
became somehow detached:
error: could not find implicit value for parameter tx: _9.Tx
id.dispose()
^
Any tricks or changes that make it work?
EDIT : To clarify, I am primarily hoping to fix the type S
in Sys
to make it work. There are numerous problems in my case using path-dependent types. To give just one example which reflects the answers of pedrofuria and Owen:
trait Foo[S <: Sys] {
val s: S
def id: s.Id
def dispose()(implicit tx: s.Tx) {
id.dispose()
}
}
trait Bar[S <: Sys] {
val s: S
def id: s.Id
def foo: Foo[S]
def dispose()(implicit tx: s.Tx) {
foo.dispose()
id.dispose()
}
}
<console>:27: error: could not find implicit value for parameter tx: _106.s.Tx
foo.dispose()
^
Try to make that def foo: Foo[s.type]
to give you an idea that this leads nowhere.
Although this doesn't answer your question (ensuring minimal modification of existing code), here's a thought:
Instead of
Tx
type being a member ofSys
, and being used inIdentifier
, I would, as a starting point, make it a parameter ofSys
, and ensure it is being used in the same way by bothId <: Identifier
andS <: Sys
, like this:This is hardly an improvement in respect to your motivation (
Sys
still has a type parameter), but my next step would be to convertTx
to type member. The only way I could make it work however, without using any sort ofval s: S
trickery (and types based on it) is to:Sys
into two traits, introducingOuterSys
as a holder ofTx
type and everything else (Sys
andIdentifier
as inner traits), and retainingSys
for whatever else it is doing for youTest
trait belong toOuterSys
Here's the code:
So although not really answering your question, or solving your problem, I was hoping it might at least give you guys some idea how to pull this through. Everything else I tried came back at me with compiler shouting for some instance of
S
and expecting a type based on it.EDIT: No real need for splitting
Sys
:Also neglected to mention the obvious - that types depend on
Sys
instance, which I guess makes sense (no sharing of identifiers between systems? transactions maybe?).No need to "test" from within
Sys
instance either, and no need fortype S <: Sys
any more (andtype S = this.type
in MySystem):