Dominykas Mostauskis Dominykas Mostauskis - 3 months ago 25
Scala Question

`Future[Option[Future[Option[X]]]]` into `Future[Option[X]]`

How to transform

Future[Option[Future[Option[X]]]]
into
Future[Option[X]]
?

If it were a
TraversableOnce
instead of
Option
I'd use the Future companion object; but what about Options?

Example:

def processAndReturnFuture(x:String):Future[String] = future(x)
def processAgainAndReturnOption(x:String):Option[String] = Some(x)

val futOpt:Future[Option[String]] = future(Some("x"))
val futOptFutOpt:Future[Option[Future[Option[String]]]] =
futOpt.map( opt =>
opt.map( x =>
processAndReturnFuture(x).map( processedX =>
processAgainAndReturnOption(processedX)
)
)
)

Answer

Updated answer

This might do the trick. What I did was to replace your first two map calls with a flatMap on the outermost Future and a pattern match on the outermost Option.

val futOptFutOpt: Future[Option[String]] =
  futOpt.flatMap {
    case None => Future.successful(None)
    case Some(x) =>
      processAndReturnFuture(x).map {
        processedX => processAgainAndReturnOption(processedX)
      }
  }

Initial answer

I presume somewhere in your code you have a map call that transforms a Future[Option[A]] into a Future[Option[Future[Option[X]]]]. Replace that map with a flatMap and drop the top-most Option layer in the result. You'll end up with Future[Option[X]]. Here's what I mean:

scala> import scala.concurrent._
import scala.concurrent._

scala> import ExecutionContext.Implicits.global
import ExecutionContext.Implicits.global

scala> val f1: Future[Option[Future[Option[String]]]] =
     | Future.successful(Some(1)).map(v => Some(Future.successful(Some(v.toString))))
f1: scala.concurrent.Future[Option[scala.concurrent.Future[Option[String]]]] = scala.concurrent.impl.Promise$DefaultPromise@6f900132

scala> val f2: Future[Option[String]] =
     | Future.successful(Some(1)).flatMap(v => Future.successful(Some(v.toString)))
f2: scala.concurrent.Future[Option[String]] = scala.concurrent.impl.Promise$DefaultPromise@2fac9a62

I'm probably not entirely correct as to what your actual context is, but you'll probably solve this by replacing a few maps with a few flatMaps.

Comments