Dear Scala developers,
Context
I have two Scala projects, called core
and infra
. The core
project contains trait definitions, while infra
contains the concrete implementations of those. Therefore, infra
depends on core
.
In the core
project, I have this trait that uses cake pattern.
trait GetSectionsOfTypeComp {
def sectionsOfType[SectionType <: SoftwareSection](implicit evidence: GetSectionsOfType[SectionType]): GetSectionsOfType[SectionType]
trait GetSectionsOfType[SectionType <: SoftwareSection] {
def getAll(dataStream: InputStream): Seq[SectionType]
}
}
where SoftwareSection
is a trait with one child:
sealed trait SoftwareSection {
def name: String
def rawAddress: SoftwareAddress
def rawSize: Long
}
case class CodeSoftwareSection(name: String, rawAddress: SoftwareAddress, rawSize: Long) extends SoftwareSection
In the infra
project, I would like to segregate the logic depending on the type parameter of the method GetSectionsOfType.sectionsOfType
. Therefore, I use type classes:
trait PeParserGetSectionsOfCodeComp extends GetSectionsOfTypeComp {
implicit val foo: GetSectionsOfType[CodeSoftwareSection] = GetSectionOfCode
override def sectionsOfType[SectionType <: SoftwareSection](implicit evidence: GetSectionsOfType[SectionType]): GetSectionsOfType[SectionType] = evidence
implicit object GetSectionOfCode extends GetSectionsOfType[CodeSoftwareSection] {
override def getAll(dataStream: InputStream): Seq[CodeSoftwareSection] = Seq(CodeSoftwareSection("code", SoftwareAddress(0), 0))
}
}
trait PeParserGetSectionsOfDataComp extends GetSectionsOfTypeComp {
implicit val bar: GetSectionsOfType[DataSoftwareSection] = GetSectionOfData
override def sectionsOfType[SectionType <: SoftwareSection](implicit evidence: GetSectionsOfType[SectionType]): GetSectionsOfType[SectionType] = evidence
implicit object GetSectionOfData extends GetSectionsOfType[DataSoftwareSection] {
override def getAll(dataStream: InputStream): Seq[DataSoftwareSection] = Seq(DataSoftwareSection("data", SoftwareAddress(0), 0))
}
}
My business logic, located in the project core
needs to call the method sectionsOfType
of an instance of GetSectionsOfType
, which will be gently injected using cake pattern.
Issue to resolve the implicit type class
As the project core
does not have (and should not have!) a dependency on the infra
project, calling the method sectionsOfType[CodeSoftwareSection].getAll(openStream)
makes the compiler angry, because it can't find any implicit value for the implicit parameter, which is normal!
Now, I can't just import all the implementations of GetSectionsOfType
because it would expose the implementation in my project core
. In order to resolve this situation, I read the article WHERE DOES SCALA LOOK FOR IMPLICITS? from the Scala docs, hoping to find another way to resolve my implicit, without creeping my project core
with a dependency on my project infra
.
Unfortunately, I could not find any way to resolve my implicit, as the project core
can't link the project infra
and the implicit parameters must be resolved at compile time.
Any proposal or alternative approach to keep the code clean ?
EDIT 3: Refactored the code with cake pattern.
EDIT 4: Add an example of call to the component in the project core
below.
trait SoftwareComp {
this: GetSectionsOfTypeComp =>
class Software(val file: File) {
def codeSections[SectionType <: SoftwareSection]: Seq[SectionType] = {
sectionsOfType[SectionType].getAll(openStream)
}
def openStream: InputStream = new FileInputStream(file)
}
}