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.
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.
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.
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.
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.
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 } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With