Reputation: 1834
Base class
abstract class BaseSourceReader[T <: BaseSource] {
/**
* Method to read data from source
*/
def readFromSource(identifier: T): Seq[String]
}
// Trait common to all source identifiers
trait BaseSource
Derived class
class XYZSourceReader(param1: String) extends BaseSourceReader[XYZBaseSource] {
override def readFromSource(identifier: XYZBaseSource): Seq[String] =
// some implementation
}
case class XYZBaseSource(
paramA: String,
paramB: Seq[String]) extends BaseSource
Now what I want to do is inject the base source reader to a generic class to make the implementation independent of source:
class MySourceTrasformerJob(
val sourceReader: BaseSourceReader[BaseSource]) {
// some code
}
And use it like this:
class MyTransformerJobApp {
val reader = new XYZSourceReader(param)
val job = MySourceTrasformerJob(reader)
}
For this code snippet to work, the compiler suggests class SourceReader is invariant in type T. You may wish to define T as +T instead. (SLS 4.5)
I tried updating the BaseSourceReader
:
- abstract class BaseSourceReader[T <: BaseSource] {
+ abstract class BaseSourceReader[+T <: BaseSource] {
but that leads to an error with the readFromSource
method error: covariant type T occurs in contravariant position in type T of value identifier.
One working solution that I found is tying the implementation to the source but its not "generic" enough implementation:
class MySourceTrasformerJob(
val sourceReader: BaseSourceReader[XYZBaseSource]) {
// some code
}
I am kind of stuck in a loop with this and trying out model updates, any suggested way to handle this but definitely sticking to the generic abstract class dependency injection?
Upvotes: 0
Views: 352
Reputation: 1241
You can get into that trouble if you have a type that needs to both be and not be covariant (or contravariant) at the same time.(which is impossible to implement. In such cases all you can do is leave it invariant) you can avoid this by re-writing your MySourceTransformerJob
like this:
case class MySourceTransformerJob[T <: BaseSource](sourceReader: BaseSourceReader[T])
I did this and with no further modification your code compiled.
This also is a more natural way of expressing your intent. After all you are designing your BaseSourceReader[T <: BaseSource]
to be generic in type T
with a lower bound. So MySourceTransformerJob
had better ask for the same requirement on T
if it is not by design putting any limitations of it's own on it.
Upvotes: 2