I am trying to create an example of a ZIO Module, that has two implementations:
My general Interface looks like this:
trait Service[R] {
def load[T <: Component](ref: CompRef): RIO[R, T]
}
Now my YAML implementation looks like:
def loadYaml[T <: Component: Decoder](ref: CompRef): RIO[Any, T] = {...}
The Decoder
is implementation specific.
The problem is now how to delegate from the Service implementation to loadYaml
.
I tried the following:
val components: Components.Service[Any] = new Components.Service[Any] {
implicit val decodeComponent: Decoder[Component] =
List[Decoder[Component]](
Decoder[DbConnection].widen,
...
).reduceLeft(_ or _)
def load[T <: Component](ref: CompRef): RIO[Any, T] = loadYaml[T] (ref)
}
This gives me:
Error:(62, 20) could not find implicit value for evidence parameter of type io.circe.Decoder[T]
loadYaml[T] (ref)
Is there a way to achieve this?
I created an example project on Github: zio-comps-module
The idea is described here: Decouple the Program from its Implementation with ZIO modules
Ok, I found a solution. All I had to do was to adjust the load
function:
def load[T <: Component](ref: CompRef): RIO[ComponentsEnv, T] = {
loadConf[Component](ref).map { case c: T => c }
}
First loadConf
with the type Component
.
Second cast result (Component
) the the result type T
.
This works but gives you ugly warnings:
[warn] /Users/mpa/dev/Github/pme123/zio-comps-module/hocon/src/pme123/zio/comps/hocon/HoconComps.scala:37:46: abstract type pattern T is unchecked since it is eliminated by erasure
[warn] loadConf[Component](ref).map { case c: T => c }
[warn] ^
[warn] /Users/mpa/dev/Github/pme123/zio-comps-module/hocon/src/pme123/zio/comps/hocon/HoconComps.scala:37:36: match may not be exhaustive.
[warn] It would fail on the following inputs: DbConnection(_, _, _, _), DbLookup(_, _, _, _), MessageBundle(_, _)
[warn] loadConf[Component](ref).map { case c: T => c }
[warn] ^
[warn] two warnings found
Update - I found a solution that get rid of the warnings:
After reading the warning unchecked since it is eliminated by erasure
for the tenth time, I remembered that this could be solved with adding ClassTag
as Context Bound.
The Service looks now
trait Service[R] {
def load[T <: Component: ClassTag](ref: CompRef): RIO[R, T]
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With