Future does not compile with Success and Failure - scala

Why this does not compile? I get the following error in the Success and Failure lines:
constructor cannot be instantiated to expected type; found :
scala.util.Success[T] required: Int
And the code:
val future = Future { 1 }
future.map {
case Success(s) => s
case Failure(f) => 0
}

Because map of a Future[Int] expects a function with domain Int, but instead you are trying to pass some function with domain Try[Int] into it.
The syntactically closest thing that works is onComplete:
import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Try, Success, Failure}
val future = Future { 1 }
future.onComplete {
case Success(s) => s
case Failure(f) => 0
}
However, this is probably not what you want, because the expressions s and 0 don't do anything, they are therefore not very interesting callbacks. Instead, you probably either want to transform the result:
future.transform {
case Success(s) => Success(s)
case Failure(f) => Success(0)
}
or recover from the failure with a 0:
future.recover {
case f: Exception => 0
}

Are you trying to do something like:
val future = Future {
1
}
future onComplete {
case Success(s) => s
case Failure(f) => 0
}

Related

How to handle exceptions matching to separate function in scala

The below is just an example to represent my case of usage,
Suppose there is a function,
def getSomeValue(request:Int):Unit = {
val retry = try {
doSomething
true
}
catch {
case _:NullPointerException => false
case _:IndexOutOfBoundsException => false
case _:Exception => true
}
if(retry)
getSomeValue(request)
}
I want to handle all the exceptions in a separate function. Like below,
def handleException = {
case _:NullPointerException => false
case _:IndexOutOfBoundsException => false
case _:Exception => true
}
And tried using it in the function as,
def getSomeValue(request:Int):Unit = {
val retry = try {
doSomething
true
}
catch handleException
if(retry)
getSomeValue(request)
}
The compiler thrown couple of errors,
Method apply is not a member of type Any
Method isDefinedAt is not a member of type Any
Could some one please let me know what I am doing wrong?
There is function recoverWith in scala.util.Try for such cases. It takes partial function which handle specified exceptions. If your Try will fall you can specify retry inside this function.
For example:
import scala.util.{Failure, Try}
def getSomeValue[A](doSomething: => A): Try[A] =
Try(doSomething).recoverWith {
case t: NullPointerException => Failure(t)
case t: IndexOutOfBoundsException => Failure(t)
case _: Exception => Try(doSomething) // retry doSomething
}
this function returns Try[A] after retry and you can handle errors on the upper-lever.
Thanks to #Luis Miguel Mejía Suárez for helping me on this,
I am able to achieve this by how he said,
def getSomeValue(request:Int):Unit = {
val result = Try(doSomething)
val retry = result match {
case Success(_) => false
case Failure(exception) => handleException(exception)
}
if(retry)
getSomeValue(request)
}
def handleException(exception: Throwable) = exception match {
case _:NullPointerException => false
case _:IndexOutOfBoundsException => false
case _:Exception => true
}
Any other answers also welcomed.

How to transform a Seq[Try] to a Try[Seq]

With Futures there is an easy way to transform Seq[Future] to a Future[Seq]:
Future.sequence(seqOfFutures)
I could not find an analog thing with Try.
It works with foldLeft but what I really like would have something like Try.sequence(seqOfTry).
Is there a reason that such a function is not provided?
How is this done properly?
Semantics:
A List of the values on Success: Success(Seq(1,2,3,4))
For Failure there are 2 possibilities:
Fails on the fist Failure and returns it. This is handled by this question: listtryt-to-trylistt-in-scala
Gathers all Failures and returns a 'compound' Failure.
Is there also a solution for the 'compound' Failure?
As per Luis' suggestion Validated is designed for error accumulation so consider traverse like so
la.traverse(_.toEither.toValidatedNec)
lb.traverse(_.toEither.toValidatedNec)
which outputs
res2: cats.data.ValidatedNec[Throwable,List[Int]] = Invalid(Chain(java.lang.RuntimeException: boom, java.lang.RuntimeException: crash))
res3: cats.data.ValidatedNec[Throwable,List[Int]] = Valid(List(1, 2, 3))
where
import cats.syntax.traverse._
import cats.instances.list._
import cats.syntax.either._
import scala.util.{Failure, Success, Try}
val la: List[Try[Int]] = List(Success(1), Success(2), Failure(new RuntimeException("boom")), Success(3), Failure(new RuntimeException("crash")))
val lb: List[Try[Int]] = List(Success(1), Success(2), Success(3))
Without error accumulation we could just sequence like so
import cats.implicits._
la.sequence
which outputs
res0: scala.util.Try[List[Int]] = Failure(java.lang.RuntimeException: boom)
This is a solution to the second question.
case class CompoundError(errs: List[Throwable]) extends Throwable
def toTry[T](list: List[Try[T]]): Try[List[T]] =
list.partition(_.isSuccess) match {
case (res, Nil) =>
Success(res.map(_.get))
case (_, errs) =>
Failure(CompoundError(errs.collect { case Failure(e) => e }))
}
The partition operation separates the successes and failures, and the match returns the appropriate value depending on whether there are any failures or not.
Previous solution:
case class CompoundError(errs: List[Throwable]) extends Throwable
def toTry[T](list: List[Try[T]]): Try[List[T]] = {
val (res, errs) = list.foldLeft((List.empty[T], List.empty[Throwable])) {
case ((res, errs), item) =>
item match {
case Success(t) => (t :: res, errs)
case Failure(e) => (res, e :: errs)
}
}
errs match {
case Nil => Success(res.reverse)
case _ => Failure(CompoundError(errs.reverse))
}
}

Matching with andThen

My (incomplete) code looks like this:
def doSomething(name: String): { implicit request =>
check(name).map {
case Something() => Ok()
case SomethingElse() => NoContent
}
.andThen {
case r: Result => logger.info(s"Request finished with status ${r.header.status}")
}
}
I get an error like this:
[error] myfile.scala:39: fruitless type test: a value of type scala.util.Try[play.api.mvc.Result] cannot also be a play.api.mvc.Result
[error] case r: Result => logger.info(s"Request finished with status ${r.header.status}")
How can I match that Try?
If you're trying to match on a Try, you need to match on its constructors, not what its constructors hold:
.andThen {
case Success(r) =>
logger.info(s"Request finished with status ${r.header.status}")
case Failure(e) => // Handle failure
}

How to know which Future fail when doing Future.sequence?

Here is an example receive part of an actor I'm working on:
def receive = {
case "begin" =>
val listOfFutures: IndexedSeq[Future[Any]] = workers.map(worker => worker ? Work("test"))
val future: Future[IndexedSeq[Any]] = Future.sequence(listOfFutures)
future onComplete {
case Success(result) => println("Eventual result: "+result)
case Failure(ex) => println("Failure: "+ex.getMessage)
}
case msg => println("A message received: "+msg)
}
When ask fails for one of the workers (in case of a timeout), sequence future completes with failure. However I want to know which worker(s) have failed. Is there a more elegant way rather than simply mapping listOfFutures one by one without using Future.sequence ?
You can use the future's recover method to map or wrap the underlying exception:
import scala.concurrent.{Future, ExecutionContext}
case class WorkerFailed(name: String, cause: Throwable)
extends Exception(s"$name - ${cause.getMessage}", cause)
def mark[A](name: String, f: Future[A]): Future[A] = f.recover {
case ex => throw WorkerFailed(name, ex)
}
import ExecutionContext.Implicits.global
val f = (0 to 10).map(i => mark(s"i = $i", Future { i / i }))
val g = Future.sequence(f)
g.value // WorkerFailed: i = 0 - / by zero
Thanks to #O__ I have come with another solution that may a better fit some some cases.
case class WorkerDone(name: String)
case class WorkerFailed(name: String)
import ExecutionContext.Implicits.global
val f = (0 to 10).map {
i => Future {i/i; WorkerDone(s"worker$i")}.recover{
case ex => WorkerFailed(s"worker$i")
}
}
val futureSeq = Future.sequence(f)
futureSeq onComplete {
case Success(list) => list.collect {case result:WorkerFailed => result}.foreach {failed => println("Failed: "+failed.name)}
case Failure(ex) => println("Exception: "+ex.getMessage)
}
// just to make sure program doesn't end before onComplete is called.
Thread.sleep(2000L)
I'm not sure that if my example is a good practice, but my aim is to know which workers did fail no matter how did they fail.

Map a Future for both Success and Failure

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.
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
}
}
Since Scala 2.12 you can use transform to map both cases:
future.transform {
case Success(_) => Try("OK")
case Failure(_) => Try("KO")
}
You also have transformWith if you prefer to use a Future instead of a Try. Check the documentation for details.
In a first step, you could do something like:
import scala.util.{Try,Success,Failure}
val g = future.map( Success(_):Try[T] ).recover{
case t => Failure(t)
}.map {
case Success(s) => ...
case Failure(t) => ...
}
where T is the type of the future result. Then you can use an implicit conversion to add this structure the Future trait as a new method:
implicit class MyRichFuture[T]( fut: Future[T] ) {
def mapAll[U]( f: PartialFunction[Try[T],U] )( implicit ec: ExecutionContext ): Future[U] =
fut.map( Success(_):Try[T] ).recover{
case t => Failure(t)
}.map( f )
}
which implements the syntax your are looking for:
val future = Future{ 2 / 0 }
future.mapAll {
case Success(i) => i + 0.5
case Failure(_) => 0.0
}
Both map and flatMap variants:
implicit class FutureExtensions[T](f: Future[T]) {
def mapAll[Target](m: Try[T] => Target)(implicit ec: ExecutionContext): Future[Target] = {
val promise = Promise[Target]()
f.onComplete { r => promise success m(r) }(ec)
promise.future
}
def flatMapAll[Target](m: Try[T] => Future[Target])(implicit ec: ExecutionContext): Future[Target] = {
val promise = Promise[Target]()
f.onComplete { r => m(r).onComplete { z => promise complete z }(ec) }(ec)
promise.future
}
}