I am trying to build a framework with a hierarchy of Context
s (that hold immutable data) and Module
s that create actors work with the data. Subclasses on Context
include more data (e.g., a RemoteContext
would have information about how to communicate with remote hosts). There are also Factory
objects to make the relevant objects, which is part of the data in the Context
.
I can define the hierarchy with sub-classes, and that works fine. Once everything is defined, a Mediator
object initializes each Module
by passing the context.
The code below shows that basic structure.
import java.{ util => ju}
trait Factory
trait Context[F <: Factory]
trait SomeContext[F <: Factory] extends Context[F]
trait MediatorModule[C <: Context[_ <: Factory]] {
def loadModule(c: C)
}
trait Mediator[C <: Context[Factory]] {
val context: C
def getModules: ju.List[MediatorModule[_ >: C]]
def run() = getModules.forEach(_.loadModule(context))
}
trait OtherFact extends Factory
trait OtherContext extends SomeContext[OtherFact]
class SomeModule extends MediatorModule[SomeContext[Factory]] {
def loadModule(c: SomeContext[Factory]): Unit = { }
}
class OtherModule extends MediatorModule[OtherContext] {
def loadModule(c: OtherContext): Unit = { }
}
class OtherContextImpl extends OtherContext {
}
class OtherMediator extends Mediator[OtherContext] {
val context: OtherContext = new OtherContextImpl
def getModules: ju.List[MediatorModule[_ >: OtherContext]] =
ju.Arrays.asList(new SomeModule,
new OtherModule)
}
(The code was originally written in Java, which is why it is using Java lists).
As written, this fails to compile:
Test.scala:78:26: type mismatch;
[error] found : SomeModule
[error] required: MediatorModule[_ >: OtherContext]
[error] Note: SomeContext[Factory] <: Any (and SomeModule <: MediatorModule[SomeContext[Factory]]), but trait MediatorModule is invariant in type C.
[error] You may wish to define C as +C instead. (SLS 4.5)
[error] ju.Arrays.asList(new SomeModule,
[error] ^
[error] one error found
Following the compiler's suggestion by declaring trait MediatorModule[+C <: Context[_ <: Factory]]
instead gives two errors:
Test.scala:52:20: covariant type C occurs in contravariant position in type C of value c
[error] def loadModule(c: C)
[error] ^
[error] Test.scala:75:29: type arguments [OtherContext] do not conform to trait Mediator's type parameter bounds [C <: Context[Factory]]
[error] class OtherMediator extends Mediator[OtherContext] {
[error] ^
I can fix one with trait Context[+F <: Factory]
but the co/contra variant error remains.
What can I do to fix that error? Also, how does +C
translate back to Java?