Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Map a Future for both Success and Failure

Tags:

scala

future

I have a Future[T] and I want to map the result, on both success and failure.

Eg, something like

val future = ... // Future[T] val mapped = future.mapAll {    case Success(a) => "OK"   case Failure(e) => "KO" } 

If I use map or flatmap, it will only map successes futures. If I use recover, it will only map failed futures. onComplete executes a callback but does not return a modified future. Transform will work, but takes 2 functions rather than a partial function, so is a bit uglier.

I know I could make a new Promise, and complete that with onComplete or onSuccess/onFailure, but I was hoping there was something I was missing that would allow me to do the above with a single PF.

like image 711
sksamuel Avatar asked Apr 13 '14 14:04

sksamuel


People also ask

What is a Scala Future?

Future represents a result of an asynchronous computation that may or may not be available yet. When we create a new Future, Scala spawns a new thread and executes its code. Once the execution is finished, the result of the computation (value or exception) will be assigned to the Future.

What is a promise and Future Scala?

Promise. The Promise is a writable, single-assignment container that completes a Future. The Promise is similar to the Future. However, the Future is about the read-side of an asynchronous operation, while the Promise is about the write-side.

Is Scala Future a Monad?

yes, then it's a monad. @ElectricCoffee no. @PabloFernandez Scala's flatMap is Haskell's >>= , and Scala's for-comprehensions are equivalent to Haskell's do notation.

What is Future sequence?

sequence takes a list of futures and transforms it into a single future of list in an asynchronous manner. For instance, assume that you have a list of independent jobs to be run simultaneously. In such a case, the list of futures can be composed into a single future of list using Future. sequence.


1 Answers

Edit 2017-09-18: As of Scala 2.12, there is a transform method that takes a Try[T] => Try[S]. So you can write

val future = ... // Future[T] val mapped = future.transform {   case Success(_) => Success("OK")   case Failure(_) => Success("KO") } 

For 2.11.x, the below still applies:

AFAIK, you can't do this directly with a single PF. And transform transforms Throwable => Throwable, so that won't help you either. The closest you can get out of the box:

val mapped: Future[String] = future.map(_ => "OK").recover{case _ => "KO"} 

That said, implementing your mapAll is trivial:

implicit class RichFuture[T](f: Future[T]) {   def mapAll[U](pf: PartialFunction[Try[T], U]): Future[U] = {     val p = Promise[U]()     f.onComplete(r => p.complete(Try(pf(r))))     p.future   } } 
like image 51
espenhw Avatar answered Oct 03 '22 02:10

espenhw