CanCatch
CanCatch
CanCatch
lets you catch NonFatal
Throwable
in the F[A]
and turned it into F[Either[Throwable, A]]
. It takes a function from Throwable
to your own error type, yet it can handle only NonFatal
ones as already mentioned.
trait CanCatch[F[_]] {
def catchNonFatal[A, B](fb: => F[B])(f: Throwable => A): F[A \/ B]
def catchNonFatalEither[A, B](fab: => F[A \/ B])(f: Throwable => A): F[A \/ B]
def catchNonFatalEitherT[A, B](fab: => EitherT[F, A, B])(f: Throwable => A): EitherT[F, A, B]
}
CanCatch.catchNonFatal
CanCatch[F].catchNonFatal[A, B]
lets you catch NonFatal
Throwable
from F[B]
and returns F[A \/ B]
.
How to Use
- IO
- Future
- Id
import scalaz.effect._
import effectie.scalaz._
val fa = CanCatch[IO].catchNonFatal(
IO(throw new RuntimeException("Something's wrong!"))
)(identity)
// fa: IO[scalaz.\/[Throwable, Nothing]] = scalaz.effect.IO$$anon$7@3fc3b107
fa.unsafePerformIO()
// res1: scalaz.\/[Throwable, Nothing] = -\/(
// a = java.lang.RuntimeException: Something's wrong!
// )
import java.util.concurrent.{ExecutorService, Executors}
import scala.concurrent.{ExecutionContext, Future, Await}
import scala.concurrent.duration._
import effectie.scalaz._
val executorService: ExecutorService = Executors.newWorkStealingPool(Runtime.getRuntime.availableProcessors())
// executorService: ExecutorService = java.util.concurrent.ForkJoinPool@6acccc99[Running, parallelism = 4, size = 2, active = 0, running = 0, steals = 2, tasks = 0, submissions = 0]
implicit val ec: ExecutionContext = ExecutionContext.fromExecutorService(executorService)
// ec: ExecutionContext = scala.concurrent.impl.ExecutionContextImpl$$anon$4@67546631
val fa = CanCatch[Future].catchNonFatal(
Future(throw new RuntimeException("Something's wrong!"))
)(identity)
// fa: Future[scalaz.\/[Throwable, Nothing]] = Future(Success(-\/(java.lang.RuntimeException: Something's wrong!)))
// Just for this example, you wouldn't want to do it in your production code
Await.result(fa, Duration.Inf)
// res3: scalaz.\/[Throwable, Nothing] = -\/(
// a = java.lang.RuntimeException: Something's wrong!
// )
Use of Id
is not recommended as Id
means having no Effect
. Use it only for some special cases like testing.
import scalaz._
import Scalaz._
import effectie.scalaz._
CanCatch[Id].catchNonFatal(
throw new RuntimeException("Something's wrong!")
)(identity)
// res5: Throwable \/ Nothing = -\/(
// a = java.lang.RuntimeException: Something's wrong!
// )
Happy Path Example
- IO
- Future
- Id
import scalaz._
import Scalaz._
import scalaz.effect._
import effectie.scalaz._
import effectie.scalaz.Effectful._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
}
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
CanCatch[F].catchNonFatal(
for {
a <- pureOf(n + 100)
b <- effectOf(doSomethingBad(a))
} yield b
)(MyError.nonFatalThrowable)
val fa = doSomething[IO](1)
// fa: IO[MyError \/ Int] = scalaz.effect.IO$$anon$7@3fc8fbf1
val result = fa.unsafePerformIO()
// result: MyError \/ Int = \/-(b = 202)
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(MyError.NonFatalThrowable(a)) =>
println(s"Result: Failed with $a")
}
// Result is 202
import java.util.concurrent.{ExecutorService, Executors}
import scala.concurrent.{ExecutionContext, Future, Await}
import scala.concurrent.duration._
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.concurrent.ExecutorServiceOps
object MyApp {
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
}
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
CanCatch[F].catchNonFatal(
for {
a <- pureOf(n + 100)
b <- effectOf(doSomethingBad(a))
} yield b
)(MyError.nonFatalThrowable)
def main(arg: Array[String]): Unit = {
val executorService: ExecutorService =
Executors.newWorkStealingPool(Runtime.getRuntime.availableProcessors())
implicit val ec: ExecutionContext = ExecutionContext.fromExecutorService(executorService)
try {
val fa = doSomething[Future](1)
println(fa)
val result = Await.result(fa, 1.second)
println(result)
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
} finally {
ExecutorServiceOps.shutdownAndAwaitTermination(executorService, 1.second)
}
}
}
MyApp.main(Array.empty)
// Future(<not completed>)
// \/-(202)
// Result is 202
Use of Id
is not recommended as Id
means having no Effect
. Use it only for some special cases like testing.
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
}
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
CanCatch[F].catchNonFatal(
for {
a <- pureOf(n + 100)
b <- effectOf(doSomethingBad(a))
} yield b
)(MyError.nonFatalThrowable)
val fa = doSomething[Id](1)
// fa: Id[MyError \/ Int] = \/-(b = 202)
fa match {
case \/-(b) =>
println(s"Result is $b")
case -\/(MyError.NonFatalThrowable(a)) =>
println(s"Result: Failed with $a")
}
// Result is 202
Unhappy Path Example
- IO
- Future
- Id
import scalaz._
import Scalaz._
import scalaz.effect._
import effectie.scalaz._
import effectie.scalaz.Effectful._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
}
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
CanCatch[F].catchNonFatal(
for {
a <- pureOf(n + 100)
b <- effectOf(doSomethingBad(a))
} yield b
)(MyError.nonFatalThrowable)
val fa = doSomething[IO](-101)
// fa: IO[MyError \/ Int] = scalaz.effect.IO$$anon$7@1da13e86
val result = fa.unsafePerformIO()
// result: MyError \/ Int = -\/(
// a = NonFatalThrowable(
// throwable = java.lang.IllegalArgumentException: n cannot be a negative number. [n: -1]
// )
// )
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(MyError.NonFatalThrowable(a)) =>
println(s"Result: Failed with $a")
}
// Result: Failed with java.lang.IllegalArgumentException: n cannot be a negative number. [n: -1]
import java.util.concurrent.{ExecutorService, Executors}
import scala.concurrent.{ExecutionContext, Future, Await}
import scala.concurrent.duration._
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.concurrent.ExecutorServiceOps
object MyApp {
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
}
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
CanCatch[F].catchNonFatal(
for {
a <- pureOf(n + 100)
b <- effectOf(doSomethingBad(a))
} yield b
)(MyError.nonFatalThrowable)
def main(args: Array[String]): Unit = {
val executorService: ExecutorService =
Executors.newWorkStealingPool(Runtime.getRuntime.availableProcessors())
implicit val ec: ExecutionContext = ExecutionContext.fromExecutorService(executorService)
try {
val fa = doSomething[Future](-101)
println(fa)
val result = Await.result(fa, 1.second)
println(result)
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
} finally {
ExecutorServiceOps.shutdownAndAwaitTermination(executorService, 1.second)
}
}
}
MyApp.main(Array.empty)
// Future(<not completed>)
// -\/(NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -1]))
// Result: Failed with NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -1])
Use of Id
is not recommended as Id
means having no Effect
. Use it only for some special cases like testing.
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
}
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
CanCatch[F].catchNonFatal(
for {
a <- pureOf(n + 100)
b <- effectOf(doSomethingBad(a))
} yield b
)(MyError.nonFatalThrowable)
val fa = doSomething[Id](-101)
// fa: Id[MyError \/ Int] = -\/(
// a = NonFatalThrowable(
// throwable = java.lang.IllegalArgumentException: n cannot be a negative number. [n: -1]
// )
// )
fa match {
case \/-(b) =>
println(s"Result is $b")
case -\/(MyError.NonFatalThrowable(a)) =>
println(s"Result: Failed with $a")
}
// Result: Failed with java.lang.IllegalArgumentException: n cannot be a negative number. [n: -1]
CanCatch.catchNonFatalEither
CanCatch[F].catchNonFatalEither[A, B]
lets you catch NonFatal
Throwable
from F[A \/ B]
and returns F[A \/ B]
.
How to Use
- IO
- Future
- Id
import scalaz._
import scalaz.effect._
import effectie.scalaz._
val fa = CanCatch[IO].catchNonFatalEither(
IO((throw new RuntimeException("Something's wrong!")): Throwable \/ Int)
)(identity)
// fa: IO[Throwable \/ Int] = scalaz.effect.IO$$anon$7@118591af
fa.unsafePerformIO()
// res19: Throwable \/ Int = -\/(
// a = java.lang.RuntimeException: Something's wrong!
// )
import java.util.concurrent.{ExecutorService, Executors}
import scala.concurrent.{ExecutionContext, Future, Await}
import scala.concurrent.duration._
import scalaz._
import effectie.scalaz._
val executorService: ExecutorService = Executors.newWorkStealingPool(Runtime.getRuntime.availableProcessors())
// executorService: ExecutorService = java.util.concurrent.ForkJoinPool@55a40840[Running, parallelism = 4, size = 4, active = 0, running = 0, steals = 3, tasks = 0, submissions = 0]
implicit val ec: ExecutionContext = ExecutionContext.fromExecutorService(executorService)
// ec: ExecutionContext = scala.concurrent.impl.ExecutionContextImpl$$anon$4@2dcb7676
val fa = CanCatch[Future].catchNonFatalEither(
Future((throw new RuntimeException("Something's wrong!")): Throwable \/ Int)
)(identity)
// fa: Future[Throwable \/ Int] = Future(Success(-\/(java.lang.RuntimeException: Something's wrong!)))
// Just for this example, you wouldn't want to do it in your production code
Await.result(fa, Duration.Inf)
// res21: Throwable \/ Int = -\/(
// a = java.lang.RuntimeException: Something's wrong!
// )
Use of Id
is not recommended as Id
means having no Effect
. Use it only for some special cases like testing.
import scalaz._
import Scalaz._
import effectie.scalaz._
CanCatch[Id].catchNonFatalEither(
(throw new RuntimeException("Something's wrong!")): Throwable \/ Int
)(identity)
// res23: Throwable \/ Int = -\/(
// a = java.lang.RuntimeException: Something's wrong!
// )
Happy Path Example
- IO
- Future
- Id
import scalaz._
import Scalaz._
import scalaz.effect._
import effectie.scalaz._
import effectie.scalaz.Effectful._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
CanCatch[F].catchNonFatalEither(
for {
aOrB <- pureOf(divide100By(n))
c <- effectOf(aOrB.map(b => doSomethingBad(b)))
} yield c
)(MyError.nonFatalThrowable)
val fa = doSomething[IO](1)
// fa: IO[MyError \/ Int] = scalaz.effect.IO$$anon$7@398a3847
val result = fa.unsafePerformIO()
// result: MyError \/ Int = \/-(b = 200)
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
// Result is 200
import java.util.concurrent.{ExecutorService, Executors}
import scala.concurrent.{ExecutionContext, Future, Await}
import scala.concurrent.duration._
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.concurrent.ExecutorServiceOps
object MyApp {
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
CanCatch[F].catchNonFatalEither(
for {
aOrB <- pureOf(divide100By(n))
c <- effectOf(aOrB.map(b => doSomethingBad(b)))
} yield c
)(MyError.nonFatalThrowable)
def main(args: Array[String]): Unit = {
val executorService: ExecutorService =
Executors.newWorkStealingPool(Runtime.getRuntime.availableProcessors())
implicit val ec: ExecutionContext = ExecutionContext.fromExecutorService(executorService)
try {
val fa = doSomething[Future](1)
println(fa)
val result = Await.result(fa, 1.second)
println(result)
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
} finally {
ExecutorServiceOps.shutdownAndAwaitTermination(executorService, 1.second)
}
}
}
MyApp.main(Array.empty)
// Future(<not completed>)
// \/-(200)
// Result is 200
Use of Id
is not recommended as Id
means having no Effect
. Use it only for some special cases like testing.
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
CanCatch[F].catchNonFatalEither(
for {
aOrB <- pureOf(divide100By(n))
c <- effectOf(aOrB.map(b => doSomethingBad(b)))
} yield c
)(MyError.nonFatalThrowable)
val fa = doSomething[Id](1)
// fa: Id[MyError \/ Int] = \/-(b = 200)
fa match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
// Result is 200
Unhappy Path Example
- IO
- Future
- Id
import scalaz._
import Scalaz._
import scalaz.effect._
import effectie.scalaz._
import effectie.scalaz.Effectful._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
CanCatch[F].catchNonFatalEither(
for {
aOrB <- pureOf(divide100By(n))
c <- effectOf(aOrB.map(b => doSomethingBad(b)))
} yield c
)(MyError.nonFatalThrowable)
val fa = doSomething[IO](-1)
// fa: IO[MyError \/ Int] = scalaz.effect.IO$$anon$7@43fce30
val result = fa.unsafePerformIO()
// result: MyError \/ Int = -\/(
// a = NonFatalThrowable(
// throwable = java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100]
// )
// )
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
// Result: Failed with NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100])
import java.util.concurrent.{ExecutorService, Executors}
import scala.concurrent.{ExecutionContext, Future, Await}
import scala.concurrent.duration._
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.concurrent.ExecutorServiceOps
object MyApp {
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
CanCatch[F].catchNonFatalEither(
for {
aOrB <- pureOf(divide100By(n))
c <- effectOf(aOrB.map(b => doSomethingBad(b)))
} yield c
)(MyError.nonFatalThrowable)
def main(args: Array[String]): Unit = {
val executorService: ExecutorService =
Executors.newWorkStealingPool(Runtime.getRuntime.availableProcessors())
implicit val ec: ExecutionContext = ExecutionContext.fromExecutorService(executorService)
try {
val fa = doSomething[Future](-1)
println(fa)
val result = Await.result(fa, 1.second)
println(result)
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
} finally {
ExecutorServiceOps.shutdownAndAwaitTermination(executorService, 1.second)
}
}
}
MyApp.main(Array.empty)
// Future(<not completed>)
// -\/(NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100]))
// Result: Failed with NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100])
Use of Id
is not recommended as Id
means having no Effect
. Use it only for some special cases like testing.
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
CanCatch[F].catchNonFatalEither(
for {
aOrB <- pureOf(divide100By(n))
c <- effectOf(aOrB.map(b => doSomethingBad(b)))
} yield c
)(MyError.nonFatalThrowable)
val fa = doSomething[Id](-1)
// fa: Id[MyError \/ Int] = -\/(
// a = NonFatalThrowable(
// throwable = java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100]
// )
// )
fa match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
// Result: Failed with NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100])
CanCatch.catchNonFatalEitherT
CanCatch[F].catchNonFatalEitherT[A, B]
lets you catch NonFatal
Throwable
from EitherT[F, A, B]
and returns EitherT[F, A, B]
.
How to Use
- IO
- Future
- Id
import scalaz._
import scalaz.effect._
import effectie.scalaz._
val fa = CanCatch[IO].catchNonFatalEitherT(
EitherT(IO((throw new RuntimeException("Something's wrong!")): Throwable \/ Int))
)(identity)
// fa: EitherT[IO, Throwable, Int] = EitherT(
// run = scalaz.effect.IO$$anon$7@712c20ff
// )
fa.run.unsafePerformIO()
// res37: Throwable \/ Int = -\/(
// a = java.lang.RuntimeException: Something's wrong!
// )
import java.util.concurrent.{ExecutorService, Executors}
import scala.concurrent.{ExecutionContext, Future, Await}
import scala.concurrent.duration._
import scalaz._
import effectie.scalaz._
val executorService: ExecutorService = Executors.newWorkStealingPool(Runtime.getRuntime.availableProcessors())
// executorService: ExecutorService = java.util.concurrent.ForkJoinPool@7a2806a[Running, parallelism = 4, size = 4, active = 0, running = 0, steals = 3, tasks = 0, submissions = 0]
implicit val ec: ExecutionContext = ExecutionContext.fromExecutorService(executorService)
// ec: ExecutionContext = scala.concurrent.impl.ExecutionContextImpl$$anon$4@6f02c8d9
val fa = CanCatch[Future].catchNonFatalEitherT(
EitherT(Future((throw new RuntimeException("Something's wrong!")): Throwable \/ Int))
)(identity)
// fa: EitherT[Future, Throwable, Int] = EitherT(
// run = Future(Success(-\/(java.lang.RuntimeException: Something's wrong!)))
// )
// Just for this example, you wouldn't want to do it in your production code
Await.result(fa.run, Duration.Inf)
// res39: Throwable \/ Int = -\/(
// a = java.lang.RuntimeException: Something's wrong!
// )
Use of Id
is not recommended as Id
means having no Effect
. Use it only for some special cases like testing.
import scalaz._
import Scalaz._
import effectie.scalaz._
val fa = CanCatch[Id].catchNonFatalEitherT(
EitherT((throw new RuntimeException("Something's wrong!")): Id[Throwable \/ Int])
)(identity)
// fa: EitherT[Id, Throwable, Int] = EitherT(
// run = -\/(a = java.lang.RuntimeException: Something's wrong!)
// )
fa.run
// res41: Id[Throwable \/ Int] = -\/(
// a = java.lang.RuntimeException: Something's wrong!
// )
Happy Path Example
- IO
- Future
- Id
import scalaz._
import Scalaz._
import scalaz.effect._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.EitherTSupport._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
CanCatch[F].catchNonFatalEitherT(
for {
b <- EitherT(pureOf(divide100By(n)))
c <- eitherTRight[MyError](doSomethingBad(b))
} yield c
)(MyError.nonFatalThrowable).run
val fa = doSomething[IO](1)
// fa: IO[MyError \/ Int] = scalaz.effect.IO$$anon$7@15b6d547
val result = fa.unsafePerformIO()
// result: MyError \/ Int = \/-(b = 200)
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
// Result is 200
import java.util.concurrent.{ExecutorService, Executors}
import scala.concurrent.{ExecutionContext, Future, Await}
import scala.concurrent.duration._
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.EitherTSupport._
import effectie.concurrent.ExecutorServiceOps
object MyApp {
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
CanCatch[F].catchNonFatalEitherT(
for {
b <- EitherT(pureOf(divide100By(n)))
c <- eitherTRight[MyError](doSomethingBad(b))
} yield c
)(MyError.nonFatalThrowable).run
def main(args: Array[String]): Unit = {
val executorService: ExecutorService =
Executors.newWorkStealingPool(Runtime.getRuntime.availableProcessors())
implicit val ec: ExecutionContext = ExecutionContext.fromExecutorService(executorService)
try {
val fa = doSomething[Future](1)
println(fa)
val result = Await.result(fa, 1.second)
println(result)
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
} finally {
ExecutorServiceOps.shutdownAndAwaitTermination(executorService, 1.second)
}
}
}
MyApp.main(Array.empty)
// Future(<not completed>)
// \/-(200)
// Result is 200
Use of Id
is not recommended as Id
means having no Effect
. Use it only for some special cases like testing.
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.EitherTSupport._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
CanCatch[F].catchNonFatalEitherT(
for {
b <- EitherT(pureOf(divide100By(n)))
c <- eitherTRight[MyError](doSomethingBad(b))
} yield c
)(MyError.nonFatalThrowable).run
val fa = doSomething[Id](1)
// fa: Id[MyError \/ Int] = \/-(b = 200)
fa match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
// Result is 200
Unhappy Path Example
- IO
- Future
- Id
import scalaz._
import Scalaz._
import scalaz.effect._
import effectie.scalaz._
import effectie.scalaz.EitherTSupport._
import effectie.scalaz.Effectful._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
CanCatch[F].catchNonFatalEitherT(
for {
b <- EitherT(pureOf(divide100By(n)))
c <- eitherTRight[MyError](doSomethingBad(b))
} yield c
)(MyError.nonFatalThrowable).run
val fa = doSomething[IO](-1)
// fa: IO[MyError \/ Int] = scalaz.effect.IO$$anon$7@50d24d6
val result = fa.unsafePerformIO()
// result: MyError \/ Int = -\/(
// a = NonFatalThrowable(
// throwable = java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100]
// )
// )
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
// Result: Failed with NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100])
import java.util.concurrent.{ExecutorService, Executors}
import scala.concurrent.{ExecutionContext, Future, Await}
import scala.concurrent.duration._
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.EitherTSupport._
import effectie.concurrent.ExecutorServiceOps
object MyApp {
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
CanCatch[F].catchNonFatalEitherT(
for {
b <- EitherT(pureOf(divide100By(n)))
c <- eitherTRight[MyError](doSomethingBad(b))
} yield c
)(MyError.nonFatalThrowable).run
def main(args: Array[String]): Unit = {
val executorService: ExecutorService =
Executors.newWorkStealingPool(Runtime.getRuntime.availableProcessors())
implicit val ec: ExecutionContext = ExecutionContext.fromExecutorService(executorService)
try {
val fa = doSomething[Future](-1)
println(fa)
val result = Await.result(fa, 1.second)
println(result)
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
} finally {
ExecutorServiceOps.shutdownAndAwaitTermination(executorService, 1.second)
}
}
}
MyApp.main(Array.empty)
// Future(<not completed>)
// -\/(NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100]))
// Result: Failed with NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100])
Use of Id
is not recommended as Id
means having no Effect
. Use it only for some special cases like testing.
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.EitherTSupport._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
CanCatch[F].catchNonFatalEitherT(
for {
b <- EitherT(pureOf(divide100By(n)))
c <- eitherTRight[MyError](doSomethingBad(b))
} yield c
)(MyError.nonFatalThrowable).run
val fa = doSomething[Id](-1)
// fa: Id[MyError \/ Int] = -\/(
// a = NonFatalThrowable(
// throwable = java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100]
// )
// )
fa match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
// Result: Failed with NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100])
Catching
Catching.catchNonFatal
provides a convenient way to use CanCatch
to catch NonFatal
Throwable
in the F[A]
and turned it into F[Either[Throwable, A]]
. Just like CanCatch
, it takes a function from Throwable
to your own error type, yet it can handle only NonFatal
ones as already mentioned.
Catching.catchNonFatal
catchNonFatal
lets you catch NonFatal
Throwable
from F[B]
and returns F[A \/ B]
.
How to Use
- IO
- Future
- Id
import scalaz.effect._
import effectie.scalaz.Catching._
val fa = catchNonFatal(
IO((throw new RuntimeException("Something's wrong!")): Int)
)(identity)
// fa: IO[scalaz.\/[Throwable, Int]] = scalaz.effect.IO$$anon$7@16bf45cd
fa.unsafePerformIO()
// res55: scalaz.\/[Throwable, Int] = -\/(
// a = java.lang.RuntimeException: Something's wrong!
// )
import java.util.concurrent.{ExecutorService, Executors}
import scala.concurrent.{ExecutionContext, Future, Await}
import scala.concurrent.duration._
import effectie.scalaz.Catching._
val executorService: ExecutorService = Executors.newWorkStealingPool(Runtime.getRuntime.availableProcessors())
// executorService: ExecutorService = java.util.concurrent.ForkJoinPool@6f0213c3[Running, parallelism = 4, size = 3, active = 0, running = 0, steals = 2, tasks = 0, submissions = 0]
implicit val ec: ExecutionContext = ExecutionContext.fromExecutorService(executorService)
// ec: ExecutionContext = scala.concurrent.impl.ExecutionContextImpl$$anon$4@4cbdef89
val fa = catchNonFatal(
Future(throw new RuntimeException("Something's wrong!"))
)(identity)
// fa: Future[scalaz.\/[Throwable, Nothing]] = Future(Success(-\/(java.lang.RuntimeException: Something's wrong!)))
// Just for this example, you wouldn't want to do it in your production code
Await.result(fa, Duration.Inf)
// res57: scalaz.\/[Throwable, Nothing] = -\/(
// a = java.lang.RuntimeException: Something's wrong!
// )
Use of Id
is not recommended as Id
means having no Effect
. Use it only for some special cases like testing.
import scalaz._
import Scalaz._
import effectie.scalaz.Catching._
catchNonFatal[Id](
throw new RuntimeException("Something's wrong!")
)(identity)
// res59: Id[Throwable \/ Nothing] = -\/(
// a = java.lang.RuntimeException: Something's wrong!
// )
Happy Path Example
- IO
- Future
- Id
import scalaz._
import Scalaz._
import scalaz.effect._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.Catching._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
}
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
catchNonFatal(
for {
a <- pureOf(n + 100)
b <- effectOf(doSomethingBad(a))
} yield b
)(MyError.nonFatalThrowable)
val fa = doSomething[IO](1)
// fa: IO[MyError \/ Int] = scalaz.effect.IO$$anon$7@207a495c
val result = fa.unsafePerformIO()
// result: MyError \/ Int = \/-(b = 202)
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(MyError.NonFatalThrowable(a)) =>
println(s"Result: Failed with $a")
}
// Result is 202
import java.util.concurrent.{ExecutorService, Executors}
import scala.concurrent.{ExecutionContext, Future, Await}
import scala.concurrent.duration._
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.Catching._
import effectie.concurrent.ExecutorServiceOps
object MyApp {
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
}
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
catchNonFatal(
for {
a <- pureOf(n + 100)
b <- effectOf(doSomethingBad(a))
} yield b
)(MyError.nonFatalThrowable)
def main(arg: Array[String]): Unit = {
val executorService: ExecutorService =
Executors.newWorkStealingPool(Runtime.getRuntime.availableProcessors())
implicit val ec: ExecutionContext = ExecutionContext.fromExecutorService(executorService)
try {
val fa = doSomething[Future](1)
println(fa)
val result = Await.result(fa, 1.second)
println(result)
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
} finally {
ExecutorServiceOps.shutdownAndAwaitTermination(executorService, 1.second)
}
}
}
MyApp.main(Array.empty)
// Future(<not completed>)
// \/-(202)
// Result is 202
Use of Id
is not recommended as Id
means having no Effect
. Use it only for some special cases like testing.
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.Catching._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
}
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
catchNonFatal(
for {
a <- pureOf(n + 100)
b <- effectOf(doSomethingBad(a))
} yield b
)(MyError.nonFatalThrowable)
val fa = doSomething[Id](1)
// fa: Id[MyError \/ Int] = \/-(b = 202)
fa match {
case \/-(b) =>
println(s"Result is $b")
case -\/(MyError.NonFatalThrowable(a)) =>
println(s"Result: Failed with $a")
}
// Result is 202
Unhappy Path Example
- IO
- Future
- Id
import scalaz._
import Scalaz._
import scalaz.effect._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.Catching._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
}
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
catchNonFatal(
for {
a <- pureOf(n + 100)
b <- effectOf(doSomethingBad(a))
} yield b
)(MyError.nonFatalThrowable)
val fa = doSomething[IO](-101)
// fa: IO[MyError \/ Int] = scalaz.effect.IO$$anon$7@4c87f1b3
val result = fa.unsafePerformIO()
// result: MyError \/ Int = -\/(
// a = NonFatalThrowable(
// throwable = java.lang.IllegalArgumentException: n cannot be a negative number. [n: -1]
// )
// )
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(MyError.NonFatalThrowable(a)) =>
println(s"Result: Failed with $a")
}
// Result: Failed with java.lang.IllegalArgumentException: n cannot be a negative number. [n: -1]
import java.util.concurrent.{ExecutorService, Executors}
import scala.concurrent.{ExecutionContext, Future, Await}
import scala.concurrent.duration._
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.Catching._
import effectie.concurrent.ExecutorServiceOps
object MyApp {
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
}
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
catchNonFatal(
for {
a <- pureOf(n + 100)
b <- effectOf(doSomethingBad(a))
} yield b
)(MyError.nonFatalThrowable)
def main(args: Array[String]): Unit = {
val executorService: ExecutorService =
Executors.newWorkStealingPool(Runtime.getRuntime.availableProcessors())
implicit val ec: ExecutionContext = ExecutionContext.fromExecutorService(executorService)
try {
val fa = doSomething[Future](-101)
println(fa)
val result = Await.result(fa, 1.second)
println(result)
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
} finally {
ExecutorServiceOps.shutdownAndAwaitTermination(executorService, 1.second)
}
}
}
MyApp.main(Array.empty)
// Future(<not completed>)
// -\/(NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -1]))
// Result: Failed with NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -1])
Use of Id
is not recommended as Id
means having no Effect
. Use it only for some special cases like testing.
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.Catching._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
}
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
catchNonFatal(
for {
a <- pureOf(n + 100)
b <- effectOf(doSomethingBad(a))
} yield b
)(MyError.nonFatalThrowable)
val fa = doSomething[Id](-101)
// fa: Id[MyError \/ Int] = -\/(
// a = NonFatalThrowable(
// throwable = java.lang.IllegalArgumentException: n cannot be a negative number. [n: -1]
// )
// )
fa match {
case \/-(b) =>
println(s"Result is $b")
case -\/(MyError.NonFatalThrowable(a)) =>
println(s"Result: Failed with $a")
}
// Result: Failed with java.lang.IllegalArgumentException: n cannot be a negative number. [n: -1]
Catching.catchNonFatalEither
Catching.catchNonFatalEither
provides a convenient way to use CanCatch
to catch NonFatal
Throwable
from F[A \/ B]
and returns F[A \/ B]
.
How to Use
- IO
- Future
- Id
import scalaz._
import scalaz.effect._
import effectie.scalaz.Catching._
val fa = catchNonFatalEither(
IO((throw new RuntimeException("Something's wrong!")): Throwable \/ Int)
)(identity)
// fa: IO[Throwable \/ Int] = scalaz.effect.IO$$anon$7@33646feb
fa.unsafePerformIO()
// res73: Throwable \/ Int = -\/(
// a = java.lang.RuntimeException: Something's wrong!
// )
import java.util.concurrent.{ExecutorService, Executors}
import scala.concurrent.{ExecutionContext, Future, Await}
import scala.concurrent.duration._
import scalaz._
import effectie.scalaz.Catching._
val executorService: ExecutorService = Executors.newWorkStealingPool(Runtime.getRuntime.availableProcessors())
// executorService: ExecutorService = java.util.concurrent.ForkJoinPool@10860fa9[Running, parallelism = 4, size = 4, active = 0, running = 0, steals = 3, tasks = 0, submissions = 0]
implicit val ec: ExecutionContext = ExecutionContext.fromExecutorService(executorService)
// ec: ExecutionContext = scala.concurrent.impl.ExecutionContextImpl$$anon$4@6244944c
val fa = catchNonFatalEither(
Future((throw new RuntimeException("Something's wrong!")): Throwable \/ Int)
)(identity)
// fa: Future[Throwable \/ Int] = Future(Success(-\/(java.lang.RuntimeException: Something's wrong!)))
// Just for this example, you wouldn't want to do it in your production code
Await.result(fa, Duration.Inf)
// res75: Throwable \/ Int = -\/(
// a = java.lang.RuntimeException: Something's wrong!
// )
Use of Id
is not recommended as Id
means having no Effect
. Use it only for some special cases like testing.
import scalaz._
import Scalaz._
import effectie.scalaz.Catching._
catchNonFatalEither[Id](
(throw new RuntimeException("Something's wrong!")): Throwable \/ Int
)(identity)
// res77: Id[Throwable \/ Int] = -\/(
// a = java.lang.RuntimeException: Something's wrong!
// )
Happy Path Example
- IO
- Future
- Id
import scalaz._
import Scalaz._
import scalaz.effect._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.Catching._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
catchNonFatalEither(
for {
aOrB <- pureOf(divide100By(n))
c <- effectOf(aOrB.map(b => doSomethingBad(b)))
} yield c
)(MyError.nonFatalThrowable)
val fa = doSomething[IO](1)
// fa: IO[MyError \/ Int] = scalaz.effect.IO$$anon$7@113debde
val result = fa.unsafePerformIO()
// result: MyError \/ Int = \/-(b = 200)
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
// Result is 200
import java.util.concurrent.{ExecutorService, Executors}
import scala.concurrent.{ExecutionContext, Future, Await}
import scala.concurrent.duration._
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.Catching._
import effectie.concurrent.ExecutorServiceOps
object MyApp {
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
catchNonFatalEither(
for {
aOrB <- pureOf(divide100By(n))
c <- effectOf(aOrB.map(b => doSomethingBad(b)))
} yield c
)(MyError.nonFatalThrowable)
def main(args: Array[String]): Unit = {
val executorService: ExecutorService =
Executors.newWorkStealingPool(Runtime.getRuntime.availableProcessors())
implicit val ec: ExecutionContext = ExecutionContext.fromExecutorService(executorService)
try {
val fa = doSomething[Future](1)
println(fa)
val result = Await.result(fa, 1.second)
println(result)
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
} finally {
ExecutorServiceOps.shutdownAndAwaitTermination(executorService, 1.second)
}
}
}
MyApp.main(Array.empty)
// Future(<not completed>)
// \/-(200)
// Result is 200
Use of Id
is not recommended as Id
means having no Effect
. Use it only for some special cases like testing.
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.Catching._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
catchNonFatalEither(
for {
aOrB <- pureOf(divide100By(n))
c <- effectOf(aOrB.map(b => doSomethingBad(b)))
} yield c
)(MyError.nonFatalThrowable)
val fa = doSomething[Id](1)
// fa: Id[MyError \/ Int] = \/-(b = 200)
fa match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
// Result is 200
Unhappy Path Example
- IO
- Future
- Id
import scalaz._
import Scalaz._
import scalaz.effect._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.Catching._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
catchNonFatalEither(
for {
aOrB <- pureOf(divide100By(n))
c <- effectOf(aOrB.map(b => doSomethingBad(b)))
} yield c
)(MyError.nonFatalThrowable)
val fa = doSomething[IO](-1)
// fa: IO[MyError \/ Int] = scalaz.effect.IO$$anon$7@136d525
val result = fa.unsafePerformIO()
// result: MyError \/ Int = -\/(
// a = NonFatalThrowable(
// throwable = java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100]
// )
// )
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
// Result: Failed with NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100])
import java.util.concurrent.{ExecutorService, Executors}
import scala.concurrent.{ExecutionContext, Future, Await}
import scala.concurrent.duration._
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.Catching._
import effectie.concurrent.ExecutorServiceOps
object MyApp {
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
catchNonFatalEither(
for {
aOrB <- pureOf(divide100By(n))
c <- effectOf(aOrB.map(b => doSomethingBad(b)))
} yield c
)(MyError.nonFatalThrowable)
def main(args: Array[String]): Unit = {
val executorService: ExecutorService =
Executors.newWorkStealingPool(Runtime.getRuntime.availableProcessors())
implicit val ec: ExecutionContext = ExecutionContext.fromExecutorService(executorService)
try {
val fa = doSomething[Future](-1)
println(fa)
val result = Await.result(fa, 1.second)
println(result)
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
} finally {
ExecutorServiceOps.shutdownAndAwaitTermination(executorService, 1.second)
}
}
}
MyApp.main(Array.empty)
// Future(<not completed>)
// -\/(NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100]))
// Result: Failed with NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100])
Use of Id
is not recommended as Id
means having no Effect
. Use it only for some special cases like testing.
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.Catching._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
catchNonFatalEither(
for {
aOrB <- pureOf(divide100By(n))
c <- effectOf(aOrB.map(b => doSomethingBad(b)))
} yield c
)(MyError.nonFatalThrowable)
val fa = doSomething[Id](-1)
// fa: Id[MyError \/ Int] = -\/(
// a = NonFatalThrowable(
// throwable = java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100]
// )
// )
fa match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
// Result: Failed with NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100])
Catching.catchNonFatalEitherT
Catching.catchNonFatalEitherT
provides a convenient way to use CanCatch
to catch NonFatal
Throwable
from EitherT[F, A, B]
and returns EitherT[F, A, B]
.
How to Use
- IO
- Future
- Id
import scalaz._
import scalaz.effect._
import effectie.scalaz.Catching._
val fa = catchNonFatalEitherT[IO](
EitherT(IO((throw new RuntimeException("Something's wrong!")): Throwable \/ Int))
)(identity)
// fa: EitherT[IO, Throwable, Int] = EitherT(
// run = scalaz.effect.IO$$anon$7@21ed79ed
// )
fa.run.unsafePerformIO()
// res91: Throwable \/ Int = -\/(
// a = java.lang.RuntimeException: Something's wrong!
// )
import java.util.concurrent.{ExecutorService, Executors}
import scala.concurrent.{ExecutionContext, Future, Await}
import scala.concurrent.duration._
import scalaz._
import effectie.scalaz.Catching._
val executorService: ExecutorService = Executors.newWorkStealingPool(Runtime.getRuntime.availableProcessors())
// executorService: ExecutorService = java.util.concurrent.ForkJoinPool@67cd7f68[Running, parallelism = 4, size = 4, active = 0, running = 0, steals = 3, tasks = 0, submissions = 0]
implicit val ec: ExecutionContext = ExecutionContext.fromExecutorService(executorService)
// ec: ExecutionContext = scala.concurrent.impl.ExecutionContextImpl$$anon$4@19d00b54
val fa = catchNonFatalEitherT[Future](
EitherT(Future((throw new RuntimeException("Something's wrong!")): Throwable \/ Int))
)(identity)
// fa: EitherT[Future, Throwable, Int] = EitherT(
// run = Future(Success(-\/(java.lang.RuntimeException: Something's wrong!)))
// )
// Just for this example, you wouldn't want to do it in your production code
Await.result(fa.run, Duration.Inf)
// res93: Throwable \/ Int = -\/(
// a = java.lang.RuntimeException: Something's wrong!
// )
Use of Id
is not recommended as Id
means having no Effect
. Use it only for some special cases like testing.
import scalaz._
import Scalaz._
import effectie.scalaz.Catching._
val fa = catchNonFatalEitherT[Id](
EitherT((throw new RuntimeException("Something's wrong!")): Id[Throwable \/ Int])
)(identity)
// fa: EitherT[Id, Throwable, Int] = EitherT(
// run = -\/(a = java.lang.RuntimeException: Something's wrong!)
// )
fa.run
// res95: Id[Throwable \/ Int] = -\/(
// a = java.lang.RuntimeException: Something's wrong!
// )
Happy Path Example
- IO
- Future
- Id
import scalaz._
import Scalaz._
import scalaz.effect._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.Catching._
import effectie.scalaz.EitherTSupport._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
catchNonFatalEitherT(
for {
b <- EitherT(pureOf(divide100By(n)))
c <- eitherTRight[MyError](doSomethingBad(b))
} yield c
)(MyError.nonFatalThrowable).run
val fa = doSomething[IO](1)
// fa: IO[MyError \/ Int] = scalaz.effect.IO$$anon$7@2e786ab6
val result = fa.unsafePerformIO()
// result: MyError \/ Int = \/-(b = 200)
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
// Result is 200
import java.util.concurrent.{ExecutorService, Executors}
import scala.concurrent.{ExecutionContext, Future, Await}
import scala.concurrent.duration._
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.Catching._
import effectie.scalaz.EitherTSupport._
import effectie.concurrent.ExecutorServiceOps
object MyApp {
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
catchNonFatalEitherT(
for {
b <- EitherT(pureOf(divide100By(n)))
c <- eitherTRight[MyError](doSomethingBad(b))
} yield c
)(MyError.nonFatalThrowable).run
def main(args: Array[String]): Unit = {
val executorService: ExecutorService =
Executors.newWorkStealingPool(Runtime.getRuntime.availableProcessors())
implicit val ec: ExecutionContext = ExecutionContext.fromExecutorService(executorService)
try {
val fa = doSomething[Future](1)
println(fa)
val result = Await.result(fa, 1.second)
println(result)
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
} finally {
ExecutorServiceOps.shutdownAndAwaitTermination(executorService, 1.second)
}
}
}
MyApp.main(Array.empty)
// Future(<not completed>)
// \/-(200)
// Result is 200
Use of Id
is not recommended as Id
means having no Effect
. Use it only for some special cases like testing.
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.Catching._
import effectie.scalaz.EitherTSupport._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
catchNonFatalEitherT(
for {
b <- EitherT(pureOf(divide100By(n)))
c <- eitherTRight[MyError](doSomethingBad(b))
} yield c
)(MyError.nonFatalThrowable).run
val fa = doSomething[Id](1)
// fa: Id[MyError \/ Int] = \/-(b = 200)
fa match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
// Result is 200
Unhappy Path Example
- IO
- Future
- Id
import scalaz._
import Scalaz._
import scalaz.effect._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.Catching._
import effectie.scalaz.EitherTSupport._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
catchNonFatalEitherT(
for {
b <- EitherT(pureOf(divide100By(n)))
c <- eitherTRight[MyError](doSomethingBad(b))
} yield c
)(MyError.nonFatalThrowable).run
val fa = doSomething[IO](-1)
// fa: IO[MyError \/ Int] = scalaz.effect.IO$$anon$7@64905c85
val result = fa.unsafePerformIO()
// result: MyError \/ Int = -\/(
// a = NonFatalThrowable(
// throwable = java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100]
// )
// )
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
// Result: Failed with NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100])
import java.util.concurrent.{ExecutorService, Executors}
import scala.concurrent.{ExecutionContext, Future, Await}
import scala.concurrent.duration._
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.Catching._
import effectie.scalaz.EitherTSupport._
import effectie.concurrent.ExecutorServiceOps
object MyApp {
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
catchNonFatalEitherT(
for {
b <- EitherT(pureOf(divide100By(n)))
c <- eitherTRight[MyError](doSomethingBad(b))
} yield c
)(MyError.nonFatalThrowable).run
def main(args: Array[String]): Unit = {
val executorService: ExecutorService =
Executors.newWorkStealingPool(Runtime.getRuntime.availableProcessors())
implicit val ec: ExecutionContext = ExecutionContext.fromExecutorService(executorService)
try {
val fa = doSomething[Future](-1)
println(fa)
val result = Await.result(fa, 1.second)
println(result)
result match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
} finally {
ExecutorServiceOps.shutdownAndAwaitTermination(executorService, 1.second)
}
}
}
MyApp.main(Array.empty)
// Future(<not completed>)
// -\/(NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100]))
// Result: Failed with NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100])
Use of Id
is not recommended as Id
means having no Effect
. Use it only for some special cases like testing.
import scalaz._
import Scalaz._
import effectie.scalaz._
import effectie.scalaz.Effectful._
import effectie.scalaz.Catching._
import effectie.scalaz.EitherTSupport._
sealed trait MyError
object MyError {
final case class NonFatalThrowable(throwable: Throwable) extends MyError
case object DivideByZero extends MyError
def nonFatalThrowable(throwable: Throwable): MyError
= NonFatalThrowable(throwable)
def divideByZero: MyError = DivideByZero
}
def divide100By(n: Int): MyError \/ Int =
if (n === 0)
MyError.divideByZero.left[Int]
else
(100 / n).right[MyError]
def doSomethingBad(n: Int): Int =
if (n < 0)
throw new IllegalArgumentException(s"n cannot be a negative number. [n: $n]")
else
n * 2
def doSomething[F[_]: Fx: CanCatch: Monad](
n: Int
): F[MyError \/ Int] =
catchNonFatalEitherT(
for {
b <- EitherT(pureOf(divide100By(n)))
c <- eitherTRight[MyError](doSomethingBad(b))
} yield c
)(MyError.nonFatalThrowable).run
val fa = doSomething[Id](-1)
// fa: Id[MyError \/ Int] = -\/(
// a = NonFatalThrowable(
// throwable = java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100]
// )
// )
fa match {
case \/-(b) =>
println(s"Result is $b")
case -\/(a) =>
println(s"Result: Failed with $a")
}
// Result: Failed with NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100])