Guillaume Massé
Guillaume Massé

Reputation: 8064

How should I join Option[Future[T]]?

I have the following code

import scala.concurrent.{Future, Await}
import scala.concurrent.duration.Duration

import scala.concurrent.ExecutionContext.Implicits.global

def later(v: Int) = Future.successful(v)

val data = List(
  (1, Some(1), Some(2)),
  (2, Some(1), None),
  (3, None, Some(2)),
  (4, None, None)
)

def wait[T](v: Future[T]) = Await.result(v, Duration.Inf)


def seq[T](v: Option[Future[T]]): Future[Option[T]] = Future.sequence(v.toList).map(_.headOption)
def join[A, B](a: Option[Future[A]], b: Option[Future[B]]): Future[(Option[A], Option[B])] = seq(a).zip(seq(b))

wait(Future.sequence(data.map{ case (a, b, c) =>
  join(b.map(later), c.map(later)).map((a, _))
})) == List(
  (1, ((Some(1), Some(2)))),
  (2, ((Some(1), None))),
  (3, ((None, Some(2)))),
  (4, ((None, None)))
)

I was wondering if there is any other way to write the join function

Upvotes: 2

Views: 230

Answers (2)

Peter Neyens
Peter Neyens

Reputation: 9820

If you are open to using Scalaz, you can omit the conversions between Option and List to be able to sequence the two values.

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

import scalaz.std.option._
import scalaz.std.scalaFuture._
import scalaz.syntax.traverse._

def join[A, B](o1: Option[Future[A]], o2: Option[Future[B]]) =
  o1.sequence zip o2.sequence

Upvotes: 3

yǝsʞǝla
yǝsʞǝla

Reputation: 16412

Without using other helper functions:

  def join[A, B](a: Option[Future[A]], b: Option[Future[B]]): Future[(Option[A], Option[B])] =
    (a, b) match {
      case (Some(fa), Some(fb)) =>
        for {
          vfa <- fa
          vfb <- fb
        } yield Some(vfa) -> Some(vfb)
      case (Some(fa), None) => fa map (Some(_) -> None)
      case (None, Some(fb)) => fb map (None -> Some(_))
      case _ => Future.successful(None -> None)
    }

Upvotes: 0

Related Questions