Given a block that catches more than one exception is it possible to handle multiple exceptions without putting the desired value in every case block? e.g. it would be nice if something like this worked:
val foo: Int = try {
//do stuff that results in an Int
} catch {
case e: SomeException => //do something if this gets thrown
case e: SomeOtherException => //do something different if this gets thrown
0
}
But that results in a compile error (type mismatch; found : Unit required: Int). I could put the default in each throwable case e: SomeException => {/*do something if this gets thrown*/; 0} - but that just seems like code smell so I'm hoping there is a more elegant solution.
You could simply wrap the exception handling:
val foo: Int = try {
//do stuff that results in an Int
17
} catch { case t: Throwable => t match {
case e: SomeException => //do something if this gets thrown
case e: SomeOtherException => //do something different if this gets thrown
}
42
}
You can take advantage of partial functions to do your error handling using the built in Try
val foo: Int ={
val value = Try{
//stuff
}
unwrap(0, value){
case x: SomeException => doStuff()
case x: OtherExcetion => doMoreStuff()
}
}
def unwrap[A](ret: A, value: Try[A])(f: Failure[A] => Unit): A = value match{
case Success(x) => x
case x: Failure => f(x); ret
}
and voila, you've handled it quite well.
The catch keyword expects a PartialFunction, which can easily be chained with andThen:
scala> val pf1: PartialFunction[Throwable, Unit] = { case _: IllegalArgumentException => println("pf1") }
pf1: PartialFunction[Throwable,Unit] = <function1>
scala> val pf2: PartialFunction[Unit, Int] = { case _ => println("pf2"); 0}
pf2: PartialFunction[Unit,Int] = <function1>
scala> try throw new IllegalArgumentException catch pf1 andThen pf2
pf1
pf2
res0: Int = 0
scala> try throw new NoSuchElementException catch pf1 andThen pf2
java.util.NoSuchElementException
The second PartialFunction is only executed when the first one matched its argument, which can be a problem when you want to catch other exceptions (that also should not return the default value). But for this case, there is orElse:
scala> val pf3: PartialFunction[Throwable, Int] = { case _ => println("pf3"); 1}
pf3: PartialFunction[Throwable,Int] = <function1>
scala> try throw new NoSuchElementException catch pf1 andThen pf2 orElse pf3
pf3
res2: Int = 1
You can use the Try object to wrap your possibly failing code, and then compose the outcome like this
val foo: Int = (Try {
//do stuff that results in an Int
} recover {
//here we handle the recovering
handleFail andThen defaultInt
}).get
val handleFail: PartialFunction[Throwable, Unit] = {
case e: SomeException => //do something if this gets thrown
case e: SomeOtherException => //do something different if this gets thrown
val defaultInt: PartialFunction[Unit, Int] = { case _ => 0 }
Related
I'm new to Scala, and I'm running into this strange situation.
def bar[A, B](implicit foo: A => B): B = {
// do something
foo
}
And then I got error like
require B but found A => B
How should I get B form A => B
Here's the reason why I did this, I have two functions:
def funcA: String = {
def getStrA: String = "A"
// then there's the same operation in both functions
Try{ } match {
case Success(_) => getStrA
case Failure(_) => // exactlly same error handler in both function
}
}
def funcB: Int = {
def doSomething(x: Int): Int = {
// do something
x / 1
}
val x = 1
Try{ } match {
case Success(_) => doSomething(1)
case Failure(_) => // exactlly same error handler in both function
}
}
Here's what I want to achieve
def funcA: String = {
implicit def getStrA: String = "A"
bar
}
def funcB: Int = {
val x = 1
implicit def doSomething(x: Int): Int = {
// do something
x / 1
}
bar
}
def bar[A, B](implicit foo: A => B): B = {
Try{ } match {
case Success(_) => foo
case Failure(_) => // exactlly same error handler in both function
}
}
You have a conversion from A to B. You need to return B. The only way to do this is to pass A into the function. This signature has an implied assumption that you have some valid A value (most likely hardcoded) that you will always use here.
def bar[A, B](implicit foo: A => B): B = {
val a: A = ... // hmm...
foo(a)
}
Considering, that A is parametric, then you are either missing some information, or this A is impossible to create (it cannot be null because not all types can take null as a value), so you might need to throw exception in such case. Probably you are either missing some A provider or you should always fail this operation.
UPDATE:
There is no need for using implicits at all in your code:
def bar[B](f: onSuccess: A => B) =
Try{ some operations } match {
case Success(value) => onSuccess(value)
case Failure(_) => // error handler
}
def funcA = bar(_ => "A")
def funcB = bar(_ => 1)
Imagine I have OptionT[IO, Value] like this
case class FailureMsg(code: String, ex: Option[Throwable])
val fff: IO[Either[FailureMsg, Int]] = OptionT.some[IO](12345)
.map { value ⇒
println("Mapping over")
value
}
.flatMapF[Int](_ ⇒ IO.raiseError(new RuntimeException("err1")))
.toRight(FailureMsg("Code0", None))
.recoverWith {
case ex ⇒ // Not Throwable!
EitherT.leftT[IO, Int](FailureMsg("Code1", Some(ex)))
}
.value
How can I catch err1 and wrap it into Left[FailureMsg]. I expected recoverWith help me but surprisingly it's alias of mapLeft. What should I do ?
I wrote helper class to do this.
implicit class EitherTExt[F[_], A, B](val obj: EitherT[F, A, B]) {
def recoverThrowable(pf: PartialFunction[Throwable, Either[A, B]])(implicit A: ApplicativeError[F, Throwable]): EitherT[F, A, B] =
EitherT(obj.value.recover(pf))
}
Let me know if there is more elegant shorter way.
I would follow the types.
val start: OptionT[IO, Int] = OptionT.some[IO](12345)
val thenMap: OptionT[IO, Int] = start.map { value ⇒
println("Mapping over")
value
}
// here it will get off the rails
val thenFlatMapF: OptionT[IO, Int] =
thenMap.flatMapF[Int](_ ⇒ IO.raiseError(new RuntimeException("err1")))
val thenToRight: EitherT[IO, FailureMsg, Int] =
thenFlatMapF.toRight(FailureMsg("Code0", None))
val result: IO[Either[FailureMsg, Int]] = thenToRight.value
thenFlatMapF won't produce OptionT[IO, Int] if IO.raiseError is the case, because no default mapping of Throwable to what? And you will get exception in folding result of IO.raiseError.
First attempt to fix it, will illustrate it:
val thenFlatMapF: OptionT[IO, Int] = thenMap.flatMapF[Int](_ ⇒ {
IO.raiseError[Option[Int]](new RuntimeException("err1")).recoverWith {
case err =>
val result: Option[Int] = ???
IO.pure(result)
}
})
How to handle error in place without breaking IO and return Option so that OptionT[IO, Int] is produced?
So basically, in this case, if you expect flatMapF to fail and need information on error, then it is better to have EitherT as its container, rather than OptionT.
Once done, possible solution shows that at some point leftMap or variance should be done to map the Throwable to FailureMsg. One of reasons is because IO has default error expressed as Throwable. One can't just mix FailureMsg and Throwable. Either inheritance is required so that FailureMsg is of type Throwable/Exception, or mapping should be done of errors in suitable places.
My rough solution would be:
val fff: IO[Either[FailureMsg, Int]] = OptionT.some[IO](12345)
// ok, let's do some input interpretation
.map { value ⇒
println("Mapping over")
value
}
// if no input, means error
.toRight(FailureMsg("Code0", None))
// if there is interpreted input to process, do it and map the errors
.flatMapF(_ ⇒ IO.raiseError[Int](new RuntimeException("err1")).attempt.map(_.leftMap {
case err: RuntimeException if err.getMessage == "err1" => FailureMsg("err1", Some(err))
// just for illustration, that if you have temptation to map on error,
// most likely there won't be only exception
case t: Throwable => FailureMsg("unexpected", Some(t))
}))
.value
However, normally contents of flatMapF would be a separate function or effect that would include error handling. Something like this:
val doJob: Int => IO[Either[FailureMsg, Int]] = arg =>
IO.raiseError[Int](new RuntimeException("err1")).attempt.map(_.leftMap {
case err: RuntimeException if err.getMessage == "err1" => FailureMsg("err1", Some(err))
case t: Throwable => FailureMsg("unexpected", Some(t))
})
val fff: IO[Either[FailureMsg, Int]] = OptionT.some[IO](12345)
.map { value ⇒
println("Mapping over")
value
}
.toRight(FailureMsg("Code0", None))
.flatMapF(arg ⇒ doJob(arg))
.value
Lately, I frequently end up writing code like that:
def doSomethingWithLotsOfConditions(arg1, arg2, arg3...) {
arg1.get(arg2) match {
case Some(value1) =>
arg3.get(value1) match {
case Some(value2) =>
arg4.get(arg5, value2) match {
case Some(value3) =>
finallyDoSomethingInside(value3)
case None =>
log("Some excuse for being unable to work with arg4/arg5...")
}
case None =>
log("Some excuse for being unable to work with arg3")
}
case None =>
log("Some excuse for being unable to work with arg1/arg2")
}
}
A somewhat related question seems to heavily advocate for such usage of nested match, although, from my point of view, it hardly seems readable, concise or easy-to-understand: (1) it kind of splits the check itself and its aftermath, (2) it makes code uncontrollably nested without any real rationale for nesting. In these particular cases, I would be glad to structure the code something in lines of:
def doSomethingWithLotsOfConditions(arg1, arg2, arg3...) {
// Step 1
val value1Opt = arg1.get(arg2)
if (value1Opt.isEmpty) {
log("Some excuse for being unable to work with arg1/arg2")
return
}
val value1 = value1Opt.get
// Step 2
val value2Opt = arg3.get(value1)
if (value2Opt.isEmpty) {
log("Some excuse for being unable to work with arg3")
return
}
val value2 = value2Opt.get
// Step 3
val value3Opt = arg4.get(arg5, value2)
if (value3Opt.isEmpty) {
log("Some excuse for being unable to work with arg4/arg5...")
return
}
val value3 = value3Opt.get
// All checked - we're free to act!
finallyDoSomethingInside(value3)
}
However, that pattern (i.e. valueXOpt = (...).get => check isEmpty => value = valueXOpt.get) looks really ugly and is also definitely too verbose. Hell, even Java version would look more concise:
Value1Type value1 = arg1.get(arg2);
if (value1 != null) {
log("Some excuse for being unable to work with arg1/arg2");
return;
}
Is there a better, cleaner alternative, i.e. for getting the value and specifying alternative short escape route (that log a line + return), without going nested with matches?
How about this?
object Options{
implicit class OptionLog[T](val option:Option[T]) extends AnyVal{
def ifNone(body: =>Unit):Option[T] = option.orElse {
body
option
}
}
}
import Options._
def something(arg1:Option[Int], arg2:Option[String], arg3:Option[Long], arg4:Option[Any]){
for{
val1 <- arg1 ifNone(println("arg1 was none"))
val2 <- arg2 ifNone(println("arg2 was none"))
val3 <- arg3 ifNone(println("arg3 was none"))
}{
println(s"doing something with $val1, $val2, $val3")
}
}
Then ...
scala> something(Some(3), Some("hello"), None, Some("blah"))
arg3 was none
scala> something(Some(3), Some("hello"), Some(10l), Some("blah"))
doing something with 3, hello, 10
Maybe you mean, for a condition x:
scala> def f(x: Option[Int]): Int = x orElse { println("nope"); return -1 } map (_ + 1) getOrElse -2
f: (x: Option[Int])Int
scala> f(Some(5))
res3: Int = 6
scala> f(None)
nope
res4: Int = -1
or even
scala> def f(x: Option[Int], y: Option[Int]): Int = (for (i <- x orElse { println("nope"); return -1 }; j <- y orElse { println("gah!"); return -2 }) yield i + j) getOrElse -3
f: (x: Option[Int], y: Option[Int])Int
scala> f(Some(5), None)
gah!
res5: Int = -2
Sorry if I'm oversimplifying.
Don't you want to use the map method?
def doSomethingWithLotsOfConditions(arg1, arg2, arg3...) =
arg1.get(arg2).map(value1 =>
arg3.get(value1).map(value2 =>
arg4.get(arg5, value2).map(value3 =>
finallyDoSomethingInside(value3)).
getOrElse(log("Some excuse for being unable to work with arg4/arg5"))).
getOrElse(log("Some excuse for being unable to work with arg3"))).
getOrElse(log("Some excuse for being unable to work with arg1/arg2"))
It is still nested but it's at least more elegant-looking than your pattern matching above.
Or you can implement your own Functor for this one:
trait Foo[+A] {
def fmap[B](f: A => B): Foo[B]
}
case class Bar[A](value: A) {
def fmap[B](f: A => B): Foo[B] = Bar(f(value))
}
case object Error[Nothing](message: String) {
def fmap[B](f: Nothing => B) = Error(message)
}
def doSomethingWithLotsOfConditions(arg1, arg2, arg3, arg4, arg5) =
arg1.get(arg2).fmap(value1 =>
arg3.get(value1).fmap(value2 =>
arg4.get(arg5, value2).fmap(value3 =>
finallyDoSomethingInside))
def processResult = doSomethingWithLotsOfConditions(...) match {
case Bar(a) => doSomething
case Error(message) => log(message)
}
This code assumes that arg.get returns a Foo.
According to Erik Meijer, as functional programmers, we all know that instead of recursion, we should use fold. How do you convert the following to use fold? I can see one way with return, but return should also be avoided in fp. Thanks!
def tryOld(string: String, original: Exception, zomOldList: List[String => Double]): Double = {
zomOldList match {
case Nil =>
throw original
case head :: tail =>
try {
head(string)
} catch {
case ex: Exception =>
tryOld(string, original, tail)
}
}
}
You can implement this with foldRight taking advantage of functions being values:
import util.control.NonFatal
def tryOld(string: String, original: Exception, zomOldList: List[String ⇒ Double]): Double = {
val unhandled: String ⇒ Double = _ ⇒ throw original
zomOldList.foldRight(unhandled) { (f, z) ⇒
x ⇒ try { f(x) } catch { case NonFatal(_) ⇒ z(x) }
}(string)
}
Note we use NonFatal here to avoid catching exceptions that we shouldn't be catching. You can write this in a more elegant way by not using exceptions directly.
You cannot implement this with a fold. A fold loops over every element of a collection, whereas tryOld will sometimes terminate early. You could take advantage of Stream's laziness and implement it in terms of collectFirst and Try:
import scala.util.Try
def tryOld(string: String, original: Exception, zomOldList: List[String => Double]): Double =
zomOldList.toStream.map(x => Try(x(string))) collectFirst {
case Success(x) => x
} getOrElse (throw original)
but your original recursive implementation is clearer and more performant.
EDIT:
If Scala had a foldRight with the same laziness properties as Haskell's foldr, then this could be defined in terms of foldRight:
implicit class GiveStreamAWorkingFoldRight[A](val s: Stream[A]) extends AnyVal {
def lazyFoldRight[B](z: => B)(f: (A, () => B) => B): B =
if (s.isEmpty) z else f(s.head, () => s.tail.lazyFoldRight(z)(f))
}
def tryOld(string: String, original: Exception, zomOldList: List[String => Double]): Double =
zomOldList.toStream.lazyFoldRight(throw original) { (a, b: () => Double) =>
try {
a(string)
} catch {
case ex: Exception => b()
}
}
However, Scala's lack of true tail-call optimization means that each call to b will introduce a new stack frame, potentially leading to a stack overflow.
Here's a solution with foldLeft. It is lengthy since I first wrote a generic function which is called by tryOldString
def tryOld[In, Error, Out](
in: In,
original: Error,
zomOldList: List[In => Either[Error, Out]]
): Either[Error, Out] = {
val seed: Either[Error, Out] = Left(original)
zomOldList.foldLeft(seed) {
case (prev, f) =>
// stores first match without return
if (seed != prev) {
prev
} else {
f(in).fold(
fa =>
prev,
fb =>
Right(fb)
)
}
}
}
def tryOutString(string: String, original: Exception, zomOldList: List[String => Double]): Double = {
val zomFunctions: List[String => Either[Exception, Double]] = zomOldList.map {
f =>
s: String =>
try {
Right(f(s))
} catch {
case e: Exception =>
Left(e)
}
}
tryOld(string, original, zomFunctions).fold(
bad => throw original,
good => good
)
}
Is there a more elegant way of doing this in scala?
def doTheDangerousThing(): Try[Result] = {
val result = Try(dangerousOp)
if (result.isFailure) {
println("error")
}
result
}
I think your if statement is perfectly valid. Here is another alternative:
def doTheDangerousThing(): Try[Result] = Try(dangerousOp) recoverWith {
case exception => println("error"); Failure(exception)
}
Something like this:
def doTheDangerousThing[Result](dangerousOp: =>Result): Try[Result] = Try(dangerousOp) match {
case o # Failure(_) => println("error"); o
case _ => _
}
Not sure if this is more idiomatic, but sometimes I find that placing the recoverWith in this manner improves readability for me:
def doDangerousThing(): Try[Result] = Try {
dangerousOp
} recoverWith {
case t: Throwable => println("error"); Failure(t)
}
My preferred,
def doTheDangerousThing(): Option[Result] = Try (dangerousOp) toOption
If the Try is successful you will get a Some(value), if it fails a None.
For a large compilation on Try uses, have a look at Try introduced in Scala 2.10.0 .
There are ways. For instance:
def doTheDangerousThing(): Try[Result] = {
val result = Try(dangerousOp)
result.failed foreach { _ =>
println("error")
}
result
}
Or, if you don't want to repeat result all through, then:
def doTheDangerousThing(): Try[Result] = {
Try(dangerousOp) recover {
case ex => println("error"); throw ex
}
}
Well, I suppose you could do something like this:
def doTheDangerousThing(): Option[Result] =
Try(dangerousOp) match {
case Success(result) => Some(result)
case Failure(e) => None //might want to log the error as well
}
In some cases I love to use two-step approach which will allow me a more granular error message control:
def retrieveData(dataId: String): Try[String] = {
Try {
Option(someApi(dataId))
.getOrElse(throw SomeApiFailedException("invalid dataId"))
} recoverWith {
case e: SomeApiFailedException => Failure(e)
case e: Throwable => Failure(SomeApiFailedException("failed retrieve dataId"))
}
}
case class SomeApiFailedException(err: String) extends RuntimeException(err)
I could choose from either of the three implementations, depending on whether I want to:
Simply propagate it upwards ( doTheDangerousThing1 )
Ignore the error ( doTheDangerousThing2 )
Intercept the error while propagating it upwards ( doTheDangerousThing3 )
Here is the code:
import scala.util.{Try,Success,Failure}
object temp {
type Result = Int
def dangerousOp = {
val r = scala.util.Random.nextInt(10)
if (r > 5) r else throw new RuntimeException("Failed on " + r)
}
def logMessage[T](t: T) = println(t)
def doTheDangerousThing1(): Try[Result] = Try(dangerousOp)
def doTheDangerousThing2(): Option[Result] = {
Try(dangerousOp) match {
case Success(r) => Option(r)
case _ => None
}
}
def doTheDangerousThing3(): Try[Result] = {
Try(dangerousOp) match {
case t # Success(r) => t
case t # _ => logMessage("failed: "+t); t
}
}
}
Inside the REPL
scala> doTheDangerousThing1
res0: scala.util.Try[Result] = Success(9)
scala> doTheDangerousThing1
res1: scala.util.Try[Result] = Success(9)
scala> doTheDangerousThing2
res2: Option[Result] = None
scala> doTheDangerousThing2
res3: Option[Result] = Some(7)
scala> doTheDangerousThing3
failed: Failure(java.lang.RuntimeException: Failed on 0)
res4: scala.util.Try[Result] = Failure(java.lang.RuntimeException: Failed on 0)
scala> doTheDangerousThing3
failed: Failure(java.lang.RuntimeException: Failed on 0)
res5: scala.util.Try[Result] = Failure(java.lang.RuntimeException: Failed on 0)