How to handle exceptions matching to separate function in scala - 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.

Related

scala tail recursion decorator not letting tail recursive function to be called

object FuncUtils {
#tailrec
def tryAll[T](funcs: (() => Any)*): Option[Any] = {
if (funcs.isEmpty) {
None
} else {
try {
Some(funcs.head())
} catch {
case _: Throwable => FuncUtils.tryAll(funcs.tail: _*)
}
}
}
}
Why? It appears to me that tryAll is self contained and the iteration can occur without referencing the call stack.
The error is not reproducible, you may try to provide more context.
Anyways, I would also recommend you to avoid Seq for tail-recursive algorithms (you should use a List instead), and try / catch blocks (use the Try Monad instead).
This is a rewrite of your code using that.
import scala.util.{Try, Success, Failure}
object FuncUtils {
def tryAll[T](funcs: (() => T)*): Option[T] = {
#annotation.tailrec
def loop(remaining: List[() => T]): Option[T] = remaining match {
case Nil => None
case x :: xs => Try(x()) match {
case Success(t) => Some(t)
case Failure(_) => loop(remaining = xs)
}
}
loop(remaining = funcs.toList)
}
}
Again, as jwvh said, yo really do not need recursion in this case.
object FuncUtils {
def tryAll[T](funcs: (() => T)*): Option[T] =
funcs.iterator.map(f => Try(f())).collectFirst { case Success(t) => t }
}
Ok the reason is because I am referring to the Singleton object that the method is contained in before calling the function.
FuncUtils.tryAll(funcs.tail: _*)
Should just be:
tryAll(funcs.tail: _*)
I guess scala can't figure out that its recursive when I reference the library.

Future does not compile with Success and Failure

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
}

How to update elegantly the Failure exception of a Try?

I would like to update the Failure exception of a Try to provide a more understandable failure.
I successfully do this by using the following implementation:
case class NoDataAvailableException() extends Exception
[...]
Try(...) match {
case Success(f) => Success(f)
case Failure(_) => Failure(NoDataAvailableException())
}
But I think this implementation is not really elegant, so my question is:
Is there a way to do this more elegantly ?
You could use recoverWith with accepts a PartialFunction[Throwable, Try[U]]. This would allow you to map specific exceptions to successes or failures, as you wish.
case class MyException() extends Exception
Try(1 / 0) recoverWith {
case _: ArithmeticException => Failure(new MyException())
// other exceptions ...
}
You could also use an implicit class to add method of your own to Try that lets you specifically map exceptions.
implicit class TryExtension[A](t: Try[A]) {
def mapFailure(pf: PartialFunction[Throwable, Throwable]): Try[A] =
t.recoverWith(pf.andThen(Failure.apply))
}
scala> Try(1 / 0).mapFailure { case _ => new MyException }
res3: scala.util.Try[Int] = Failure(MyException)
You are looking for Try.recoverWith
Try(...) recoverWith {
case _ => Failure(NoDataAvailableException())
}
How about using try.recover or try.recoverWith?

Generic Try[T] function

I want to refactor some common error handling logic in a generic Try[T] handler, similar to this:
def handler[T](t: Try[T], successFunc: T => Unit) = {
t.map {
case Success(res) => { // type mismatch required T, found Any (in successFunc line)
//case Success(res: T) => { // Type abstract type pattern T is unchecked since it is eliminated by erasure
successFunc(res)
}
case Failure(e: CustomException) => {
// custom actions
}
case Failure(e) => {
// custom actions
}
}
}
Seems I can't match against the type T because of type erasure. But I can't pass an Any to successFunc.
How can I implement this function?
Mapping on a try applies a function to the value held by a success of that try, what you have there is not a Success or a Failure, it's a T, what you want is a match:
def handler[T](t: Try[T], successFunc: T => Unit) = {
t match {
case Success(res) =>
successFunc(res)
case Failure(e: FileNotFoundException) =>
case Failure(e) =>
}
}
The usage in your case of map would be:
t.map(someT => successFunc(someT))

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.