Dominykas Mostauskis
Dominykas Mostauskis

Reputation: 8125

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

How would one transform Future[Option[X]] into Option[Future[X]]?

val futOpt:Future[Option[Int]] = future(Some(1))
val optFut:Option[Future[Int]] = ?

Update:

This is a follow up to this question. I suppose I'm trying to get a grasp on elegantly transforming nested futures. I'm trying to achieve with Options what can be done with Sequences, where you turn a Future[Seq[Future[Seq[X]]]] into Future[Future[Seq[Seq[x]]]] and then flatMap the double layers. As Ionut has clarified, I have phrased the question in flipped order, it was supposed to be Option[Future[X]] -> Future[Option[X]].

Upvotes: 11

Views: 6226

Answers (2)

anirudh.vyas
anirudh.vyas

Reputation: 572

you could technically you could do this - in snippet below I use A context bound to a monoid so my types hold.


  def fut2Opt[A: Monoid](futOpt: Future[Option[A]])(implicit ec: ExecutionContext): Option[Future[A]] =
    Try(futOpt.flatMap {
      case Some(a) => Future.successful(a)
      case None    => Future.fromTry(Try(Monoid[A].empty))
    }).toOption

Upvotes: 0

Ionuț G. Stan
Ionuț G. Stan

Reputation: 179119

Unfortunately, this isn't possible without losing the non-blocking properties of the computation. It's pretty simple if you think about it. You don't know whether the result of the computation is None or Some until that Future has completed, so you have to Await on it. At that point, it makes no sense to have a Future anymore. You can simply return the Option[X], as the Future has completed already.

Take a look here. It always returns Future.successful, which does no computation, just wraps o in a Future for no good reason.

def transform[A](f: Future[Option[A]]): Option[Future[A]] =
  Await.result(f, 2.seconds).map(o => Future.successful(o))

So, if in your context makes sense to block, you're better off using this:

def transform[A](f: Future[Option[A]]): Option[A] =
  Await.result(f, 2.seconds)

Response for comments:

def transform[A](o: Option[Future[A]]): Future[Option[A]] =
  o.map(f => f.map(Option(_))).getOrElse(Future.successful(None))

Upvotes: 32

Related Questions