I started experimenting with ZIO, and was trying to run the following highly sophisticated program:
import logger.{Logger, _}
import zio.console._
import zio.{system, _}
object MyApp extends App {
override def run(args: List[String]): ZIO[ZEnv, Nothing, Int] = {
app
.provideSome[Logger](_ => Slf4jLogger.create) //1
.fold(_ => 1, _ => 0)
}
val app: ZIO[Console with system.System with Logger, SecurityException, Unit] =
for {
_ <- info("This message from the logger") //2
maybeUser <- system.env("USER")
_ <- maybeUser match {
case Some(userName) => putStrLn(s"Hello ${userName}!")
case None => putStrLn("I don't know your name")
}
} yield ()
}
(Slf4jLogger is https://github.com/NeQuissimus/zio-slf4j)
If I comment lines //1
and //2
out everything works fine. But in the above form I get a type mismatch error:
Error:(13, 45) type mismatch;
found : logger.Slf4jLogger
required: zio.console.Console with zio.system.System with logger.Logger
.provideSome[Logger](_ => Slf4jLogger.create)
I don't understand the following:
The program required a
Console
and aSystem
instance in the environment, yet I did not have to.provide
it before, when I was not logging. Why? And why do I suddenly need it?According to the scaladoc,
.provideSome
Provides *some* of the environment required to run this effect, leaving the remainder R0. For me that means that I don't have to provide the full environment type, I could add the required modules one by one - yet it seems to expect the full ZEnv type, just like.provide
- so what's the point?I cannot instantiate an anonymous class by
new Logger with Console.Live with system.System.Live
, because the Slf4jLogger has a factory method in the companion object. How can I use this factory method with the other traits?Since creating a logger instance in Java is kind of effectful, is
.provide
even the right function to call?
PS: I was able to get this working in a kind of ugly way:
app
.provideSome[ZEnv](_ =>
new Console with Logger with system.System {
override val console = Console.Live.console
override val system = System.Live.system
override val logger = Slf4jLogger.create.logger
}
) //1
.fold(_ => 1, _ => 0)
This compiles and runs, but overriding the mixed in traits' inner members does not seem right...
And it works in exactly the same way with .provide
:
app
.provide(
new Console with Logger with system.System {
override val console = Console.Live.console
override val system = System.Live.system
override val logger = Slf4jLogger.create.logger
}
) //1
.fold(_ => 1, _ => 0)
What is going on?