Scala, ZIO - convert Future[Either[...]] into ZIO

Viewed 72

I have a simple method which returns Future[Either[Throwable, MyValue]]. Now I would like to convert it to ZIO. I created:

def zioMethod(): ZIO[Any, Throwable, MyValue] =
    ZIO.fromFuture {implicit ec =>
       futureEitherMethod().flatMap { result => 
            Future(result)
       }
    }

But it didn't work without trace: No implicit found for parameter trace: Trace.

So, after I added Trace as implicit it still doesn't work correctly. Is any other way to convert Future[Either[,]] into ZIO? Docs are not clear in this topic.

1 Answers

The signature (in the code or in the scaladoc) seems to be rather clear on this topic:

ZIO.fromFuture[A] converts a Future[A] into a ZIO[Any, Throwable, A].

You pass in a Future[Either[Throwable, MyValue]], so it would return a ZIO[Any, Throwable, Either[Throwable, MyValue]] - not a ZIO[Any, Throwable, MyValue] as your code expects.

To transfer the Left case of your Either onto the "error channel" of the ZIO, you have several options, e.g.:

Convert Future[Either[Throwable, MyValue]] to Future[MyValue] and then to ZIO:

def zioMethod(): ZIO[Any, Throwable, MyValue] =
  ZIO.fromFuture { implicit ec =>
    futureEitherMethod().flatMap { 
      case Right(myValue)  => Future.successful(myValue)
      case Left(throwable) => Future.failed(throwable)
    }
  }

Convert to ZIO[Any, Throwable, Either[Throwable, MyValue]] and then to ZIO[Any, Throwable, MyValue]:

def zioMethod(): ZIO[Any, Throwable, MyValue] = {
  val fromFuture: ZIO[Any, Throwable, Either[Throwable, MyValue]] =
    ZIO.fromFuture { implicit ec =>
      futureEitherMethod()
    }
  fromFuture.flatMap(ZIO.fromEither)
}

BTW: for me, this compiles without bringing any additional implicits in code: https://scastie.scala-lang.org/dRefNpH0SEO5aIjegV8RKw

Update: alternative (more idiomatic?) solution As pointed out in the comments by @LMeyer, there's also ZIO.absolve and to me, that seems to be the more ZIO-idiomatic way (I have close to zero experience with ZIO myself):

ZIO.fromFuture { implicit ec =>
  futureEitherMethod()
}.absolve
Related