Scala Option[Future[T]] to Future[Option[T]]

import scala.concurrent.Future
import scala.concurrent.ExecutionContext

def f[A](x: Option[Future[A]])(implicit ec: ExecutionContext): Future[Option[A]] = 
  x match {
     case Some(f) => f.map(Some(_))
     case None    => Future.successful(None)
  }

Examples:

scala> f[Int](Some(Future.successful(42)))
res3: scala.concurrent.Future[Option[Int]] = Success(Some(42))

scala> f[Int](None)
res4: scala.concurrent.Future[Option[Int]] = scala.concurrent.impl.Promise$KeptPromise@c88a337

If you have cats as a dependency in your application, the most beautiful way would be to use traverse

import cats._
import cats.implicits._

val customerAddresses = for {
  a  <- addressDAO.insert(ca.address)                 // Future[Address]
  ia <- ca.invoiceAddress.traverse(addressDAO.insert) // Future[Option[Address]]
} yield (a, ia)

The standard library does provide the methods to use Future.sequence on an Option, unfortunately you have to plumb them together.

Either as a quick method:

def swap[M](x: Option[Future[M]]): Future[Option[M]] =
    Future.sequence(Option.option2Iterable(x)).map(_.headOption)

Note I found the implicit Option.option2Iterable was already in scope for me. So you may not need to provide it, reducing the code down to Future.sequence(x).map(_.headOption)

Or you may prefer an extension method:

implicit class OptionSwitch[A](f: Option[Future[A]]) {
    import scala.concurrent.Future

    def switch: Future[Option[A]] = Future.sequence(Option.option2Iterable(f))
      .map(_.headOption)
  }


val myOpt = Option(Future(3))
myOpt.switch

Tags:

Scala

Future