Lgd. Viktor Klang

Systems all the way down

Viktor Klang bio photo


This is the fourth of several posts describing the evolution of scala.concurrent.Future in Scala 2.12.x. For the previous post, click here.

Missing canonical combinators: transformWith

As we saw in the previous post, transform provides a nice unification of both map and recover on Future, and I know what you’re thinking now: “What about flatMap and recoverWith?”

Say no more! transformWith is the answer, and has the following lovely signature:

def transformWith[S](f: Try[T] => Future[S])(implicit executor: ExecutionContext): Future[S]

Remember to use the solution with the least power which will suffice for the task at hand, so prefer to use the flatMaps and the recoverWiths primarily, opting for the transformWith as required.

And, before you say anything, yes, flatMap and recoverWith are implemented in terms of transformWith in Scala 2.12!

EDIT:

Here’s flatMap:

def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): Future[S] = transformWith {
    case Success(s) => f(s)
    case Failure(_) =>
      //Safe cast to reuse current, failed, Future
      this.asInstanceOf[Future[S]]
  }

And here’s recoverWith:

 def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] =
    transformWith {
      case Failure(t) =>
        //Pass along current failure if no match
        pf.applyOrElse(t, (_: Throwable) => this)
      case Success(_) => this
    }

Benefits:

  1. Ultimate power, for when you require it

Click here for the next part in this blog series.

Cheers,