Skip to content

Latest commit

 

History

History
61 lines (39 loc) · 2.59 KB

Futures-in-Scala-2.12-part-3.md

File metadata and controls

61 lines (39 loc) · 2.59 KB

#Futures in Scala 2.12 (part 3)

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

##Missing canonical combinators: transform

Now, if you're thinking "Hey Viktor, there's already a transform-method on Future!" then you're most definitely right. And I'll explain myself.

When the old transform1 was added, many moons ago, it was a means of mapping over successes and failures. However, the astute reader might notice that it is asymmetric: an exception thrown when mapping over the successful case will result in a failed Future, but there is no way to turn a failed case into a successful one.

One way of looking at a scala.concurrent.Future is that it's an "Eventually[Try[_]]", in other words, a container which will eventually contain a scala.util.Try parameterized by some type.

What if we had a way to transform Future more generically, and symmetrically?

Perhaps its signature ought to look something like this:

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

So for instance, that would mean that Future.map could be implemented as follows (and is!):

  def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = transform(_.map(f))

And Future.recover is possible to implement as this (and is!):

def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] =
    transform { _ recover pf }

It also makes it dead simple to lift a Future[T] to a Future[Try[T]]:

val someFuture: Future[String] =val lifted/*: Future[Try[String]]*/ = someFuture.transform(Try(_))

Nice, right?

###Benefits:

  1. Strictly more powerful / generic than the previous transform-method
  2. Straightforward to consume/transform a Futures Try[_] without having to use onComplete or unboxing Future.value
  3. For implementors of the Future trait, less methods to implement

Here's the RSS feed of this blog and—as I love feedback—please share your thoughts.

Click here for the next part in this blog series.

Cheers, √

1:

def transform[S](s: T => S, f: Throwable => Throwable)(implicit executor: ExecutionContext): Future[S]