Skip to main content

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[Either[A, B]]
def catchNonFatalEither[A, B](fab: => F[Either[A, B]])(f: Throwable => A): F[Either[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[Either[A, B]].

How to Use#

import monix.eval._
import effectie.monix._
val fa = CanCatch[Task].catchNonFatal(
Task(throw new RuntimeException("Something's wrong!"))
)(identity)
// fa: Task[Either[Throwable, Nothing]] = Map(
// source = FlatMap(
// source = Eval(thunk = <function0>),
// f = <function1>,
// trace = null
// ),
// f = effectie.monix.CanCatch$$anon$1$$Lambda$11212/0x000000010362c840@113b5525,
// trace = StackTrace(
// stackTrace = List(
// monix.eval.internal.TaskTracing$.buildFrame(TaskTracing.scala:52),
// monix.eval.internal.TaskTracing$.buildCachedFrame(TaskTracing.scala:43),
// monix.eval.internal.TaskTracing$.cached(TaskTracing.scala:38),
// monix.eval.Task.map(Task.scala:2027),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:32),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:28),
// repl.MdocSession$App0$.<clinit>(can-catch.md:19),
// repl.MdocSession$App.<init>(can-catch.md:5),
// repl.MdocSession$.app(can-catch.md:3),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withErr(Console.scala:193),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withOut(Console.scala:164),
// mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:88),
// mdoc.internal.markdown.MarkdownBuilder$.buildDocument(MarkdownBuilder.scala:44),
// mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:185),
// mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:152),
// mdoc.internal.markdown.Processor.processDocument(Processor.scala:52),
// mdoc.internal.markdown.Markdown$.toMarkdown(Markdown.scala:131),
// mdoc.internal.cli.MainOps.handleMarkdown(MainOps.scala:82),
// mdoc.internal.cli.MainOps.handleFile(MainOps.scala:110),
// mdoc.internal.cli.MainOps.$anonfun$generateCompleteSite$1(MainOps.scala:156),
// scala.collection.LinearSeqOps.foldLeft(LinearSeq.scala:169),
// scala.collection.LinearSeqOps.foldLeft$(LinearSeq.scala:165),
// scala.collection.immutable.List.foldLeft(List.scala:79),
// mdoc.internal.cli.MainOps.generateCompleteSite(MainOps.scala:155),
// mdoc.internal.cli.MainOps.run(MainOps.scala:177),
// mdoc.internal.cli.MainOps$.process(MainOps.scala:269),
// mdoc.Main$.process(Main.scala:26),
// mdoc.Main$.process(Main.scala:21),
// mdoc.Main$.main(Main.scala:16),
// ...
import monix.execution.Scheduler.Implicits.global
fa.runSyncUnsafe()
// res1: Either[Throwable, Nothing] = Left(
// value = java.lang.RuntimeException: Something's wrong!
// )

Happy Path Example#

import cats._
import cats.syntax.all._
import monix.eval._
import effectie.monix._
import effectie.monix.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[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
CanCatch[F].catchNonFatal(
for {
a <- pureOf(n + 100)
b <- effectOf(doSomethingBad(a))
} yield b
)(MyError.nonFatalThrowable)
val fa = doSomething[Task](1)
// fa: Task[Either[MyError, Int]] = Map(
// source = FlatMap(
// source = FlatMap(
// source = Now(value = 101),
// f = <function1>,
// trace = StackTrace(
// stackTrace = List(
// monix.eval.internal.TaskTracing$.buildFrame(TaskTracing.scala:52),
// monix.eval.internal.TaskTracing$.buildCachedFrame(TaskTracing.scala:43),
// monix.eval.internal.TaskTracing$.cached(TaskTracing.scala:38),
// monix.eval.Task.flatMap(Task.scala:1792),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:39),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:33),
// cats.FlatMap$Ops.flatMap(FlatMap.scala:229),
// cats.FlatMap$Ops.flatMap$(FlatMap.scala:229),
// cats.FlatMap$ToFlatMapOps$$anon$2.flatMap(FlatMap.scala:243),
// repl.MdocSession$App6$$anonfun$doSomething$1.apply(can-catch.md:120),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:32),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:28),
// repl.MdocSession$App6$.doSomething(can-catch.md:123),
// repl.MdocSession$App6$.<clinit>(can-catch.md:126),
// repl.MdocSession$App4$.<clinit>(can-catch.md:77),
// repl.MdocSession$App2$.<clinit>(can-catch.md:60),
// repl.MdocSession$App0$.<clinit>(can-catch.md:28),
// repl.MdocSession$App.<init>(can-catch.md:5),
// repl.MdocSession$.app(can-catch.md:3),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withErr(Console.scala:193),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withOut(Console.scala:164),
// mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:88),
// mdoc.internal.markdown.MarkdownBuilder$.buildDocument(MarkdownBuilder.scala:44),
// mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:185),
// mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:152),
// ...
import monix.execution.Scheduler.Implicits.global
val result = fa.runSyncUnsafe()
// result: Either[MyError, Int] = Right(value = 202)
result match {
case Right(b) =>
println(s"Result is $b")
case Left(MyError.NonFatalThrowable(a)) =>
println(s"Result: Failed with $a")
}
// Result is 202

Unhappy Path Example#

import cats._
import cats.syntax.all._
import monix.eval._
import effectie.monix._
import effectie.monix.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[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
CanCatch[F].catchNonFatal(
for {
a <- pureOf(n + 100)
b <- effectOf(doSomethingBad(a))
} yield b
)(MyError.nonFatalThrowable)
val fa = doSomething[Task](-101)
// fa: Task[Either[MyError, Int]] = Map(
// source = FlatMap(
// source = FlatMap(
// source = Now(value = -1),
// f = <function1>,
// trace = StackTrace(
// stackTrace = List(
// monix.eval.internal.TaskTracing$.buildFrame(TaskTracing.scala:52),
// monix.eval.internal.TaskTracing$.buildCachedFrame(TaskTracing.scala:43),
// monix.eval.internal.TaskTracing$.cached(TaskTracing.scala:38),
// monix.eval.Task.flatMap(Task.scala:1792),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:39),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:33),
// cats.FlatMap$Ops.flatMap(FlatMap.scala:229),
// cats.FlatMap$Ops.flatMap$(FlatMap.scala:229),
// cats.FlatMap$ToFlatMapOps$$anon$2.flatMap(FlatMap.scala:243),
// repl.MdocSession$App12$$anonfun$doSomething$7.apply(can-catch.md:323),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:32),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:28),
// repl.MdocSession$App12$.doSomething(can-catch.md:326),
// repl.MdocSession$App12$.<clinit>(can-catch.md:329),
// repl.MdocSession$App10$.<clinit>(can-catch.md:280),
// repl.MdocSession$App8$.<clinit>(can-catch.md:223),
// repl.MdocSession$App6$.<clinit>(can-catch.md:143),
// repl.MdocSession$App4$.<clinit>(can-catch.md:77),
// repl.MdocSession$App2$.<clinit>(can-catch.md:60),
// repl.MdocSession$App0$.<clinit>(can-catch.md:28),
// repl.MdocSession$App.<init>(can-catch.md:5),
// repl.MdocSession$.app(can-catch.md:3),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withErr(Console.scala:193),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withOut(Console.scala:164),
// mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:88),
// mdoc.internal.markdown.MarkdownBuilder$.buildDocument(MarkdownBuilder.scala:44),
// mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:18...
import monix.execution.Scheduler.Implicits.global
val result = fa.runSyncUnsafe()
// result: Either[MyError, Int] = Left(
// value = NonFatalThrowable(
// throwable = java.lang.IllegalArgumentException: n cannot be a negative number. [n: -1]
// )
// )
result match {
case Right(b) =>
println(s"Result is $b")
case Left(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[Either[A, B]] and returns F[Either[A, B]].

How to Use#

import monix.eval._
import effectie.monix._
val fa = CanCatch[Task].catchNonFatalEither(
Task((throw new RuntimeException("Something's wrong!")): Either[Throwable, Int])
)(identity)
// fa: Task[Either[Throwable, Int]] = Map(
// source = Map(
// source = FlatMap(
// source = Eval(thunk = <function0>),
// f = <function1>,
// trace = null
// ),
// f = effectie.monix.CanCatch$$anon$1$$Lambda$11212/0x000000010362c840@5084272d,
// trace = StackTrace(
// stackTrace = List(
// monix.eval.internal.TaskTracing$.buildFrame(TaskTracing.scala:52),
// monix.eval.internal.TaskTracing$.buildCachedFrame(TaskTracing.scala:43),
// monix.eval.internal.TaskTracing$.cached(TaskTracing.scala:38),
// monix.eval.Task.map(Task.scala:2027),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:32),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:28),
// repl.MdocSession$App0$.<clinit>(can-catch.md:19),
// repl.MdocSession$App.<init>(can-catch.md:5),
// repl.MdocSession$.app(can-catch.md:3),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withErr(Console.scala:193),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withOut(Console.scala:164),
// mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:88),
// mdoc.internal.markdown.MarkdownBuilder$.buildDocument(MarkdownBuilder.scala:44),
// mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:185),
// mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:152),
// mdoc.internal.markdown.Processor.processDocument(Processor.scala:52),
// mdoc.internal.markdown.Markdown$.toMarkdown(Markdown.scala:131),
// mdoc.internal.cli.MainOps.handleMarkdown(MainOps.scala:82),
// mdoc.internal.cli.MainOps.handleFile(MainOps.scala:110),
// mdoc.internal.cli.MainOps.$anonfun$generateCompleteSite$1(MainOps.scala:156),
// scala.collection.LinearSeqOps.foldLeft(LinearSeq.scala:169),
// scala.collection.LinearSeqOps.foldLeft$(LinearSeq.scala:165),
// scala.collection.immutable.List.foldLeft(List.scala:79),
// mdoc.internal.cli.MainOps.generateCompleteSite(MainOps.scala:155),
// mdoc.internal.cli.MainOps.run(MainOps.scala:177),
// ...
import monix.execution.Scheduler.Implicits.global
fa.runSyncUnsafe()
// res19: Either[Throwable, Int] = Left(
// value = java.lang.RuntimeException: Something's wrong!
// )

Happy Path Example#

import cats._
import cats.syntax.all._
import monix.eval._
import effectie.monix._
import effectie.monix.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): Either[MyError, Int] =
if (n === 0)
MyError.divideByZero.asLeft[Int]
else
(100 / n).asRight[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[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
CanCatch[F].catchNonFatalEither(
for {
aOrB <- pureOf(divide100By(n))
c <- effectOf(aOrB.map(b => doSomethingBad(b)))
} yield c
)(MyError.nonFatalThrowable)
val fa = doSomething[Task](1)
// fa: Task[Either[MyError, Int]] = Map(
// source = Map(
// source = FlatMap(
// source = FlatMap(
// source = Now(value = Right(value = 100)),
// f = <function1>,
// trace = StackTrace(
// stackTrace = List(
// monix.eval.internal.TaskTracing$.buildFrame(TaskTracing.scala:52),
// monix.eval.internal.TaskTracing$.buildCachedFrame(TaskTracing.scala:43),
// monix.eval.internal.TaskTracing$.cached(TaskTracing.scala:38),
// monix.eval.Task.flatMap(Task.scala:1792),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:39),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:33),
// cats.FlatMap$Ops.flatMap(FlatMap.scala:229),
// cats.FlatMap$Ops.flatMap$(FlatMap.scala:229),
// cats.FlatMap$ToFlatMapOps$$anon$2.flatMap(FlatMap.scala:243),
// repl.MdocSession$App24$$anonfun$doSomething$13.apply(can-catch.md:609),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:32),
// effectie.monix.CanCatch$$anon$1.catchNonFatalEither(CanCatch.scala:37),
// effectie.monix.CanCatch$$anon$1.catchNonFatalEither(CanCatch.scala:28),
// repl.MdocSession$App24$.doSomething(can-catch.md:612),
// repl.MdocSession$App24$.<clinit>(can-catch.md:615),
// repl.MdocSession$App22$.<clinit>(can-catch.md:555),
// repl.MdocSession$App20$.<clinit>(can-catch.md:538),
// repl.MdocSession$App18$.<clinit>(can-catch.md:506),
// repl.MdocSession$App16$.<clinit>(can-catch.md:483),
// repl.MdocSession$App14$.<clinit>(can-catch.md:426),
// repl.MdocSession$App12$.<clinit>(can-catch.md:346),
// repl.MdocSession$App10$.<clinit>(can-catch.md:280),
// repl.MdocSession$App8$.<clinit>(can-catch.md:223),
// repl.MdocSession$App6$.<clinit>(can-catch.md:143),
// repl.MdocSession$App4$.<clinit>(can-catch.md:77),
// repl.MdocSession$App2$.<clinit>(can-catch.md:60),
// repl.MdocSession$App0$.<clinit>(can-catch.md:28),
// repl.MdocSession$App.<init>(can-catch.md:5),
// repl.MdocSession$.app(can-catch.md:3),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withErr(Console.scala:193),
// ...
import monix.execution.Scheduler.Implicits.global
val result = fa.runSyncUnsafe()
// result: Either[MyError, Int] = Right(value = 200)
result match {
case Right(b) =>
println(s"Result is $b")
case Left(a) =>
println(s"Result: Failed with $a")
}
// Result is 200

Unhappy Path Example#

import cats._
import cats.syntax.all._
import monix.eval._
import effectie.monix._
import effectie.monix.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): Either[MyError, Int] =
if (n === 0)
MyError.divideByZero.asLeft[Int]
else
(100 / n).asRight[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[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
CanCatch[F].catchNonFatalEither(
for {
aOrB <- pureOf(divide100By(n))
c <- effectOf(aOrB.map(b => doSomethingBad(b)))
} yield c
)(MyError.nonFatalThrowable)
val fa = doSomething[Task](-1)
// fa: Task[Either[MyError, Int]] = Map(
// source = Map(
// source = FlatMap(
// source = FlatMap(
// source = Now(value = Right(value = -100)),
// f = <function1>,
// trace = StackTrace(
// stackTrace = List(
// monix.eval.internal.TaskTracing$.buildFrame(TaskTracing.scala:52),
// monix.eval.internal.TaskTracing$.buildCachedFrame(TaskTracing.scala:43),
// monix.eval.internal.TaskTracing$.cached(TaskTracing.scala:38),
// monix.eval.Task.flatMap(Task.scala:1792),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:39),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:33),
// cats.FlatMap$Ops.flatMap(FlatMap.scala:229),
// cats.FlatMap$Ops.flatMap$(FlatMap.scala:229),
// cats.FlatMap$ToFlatMapOps$$anon$2.flatMap(FlatMap.scala:243),
// repl.MdocSession$App30$$anonfun$doSomething$19.apply(can-catch.md:844),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:32),
// effectie.monix.CanCatch$$anon$1.catchNonFatalEither(CanCatch.scala:37),
// effectie.monix.CanCatch$$anon$1.catchNonFatalEither(CanCatch.scala:28),
// repl.MdocSession$App30$.doSomething(can-catch.md:847),
// repl.MdocSession$App30$.<clinit>(can-catch.md:850),
// repl.MdocSession$App28$.<clinit>(can-catch.md:790),
// repl.MdocSession$App26$.<clinit>(can-catch.md:722),
// repl.MdocSession$App24$.<clinit>(can-catch.md:632),
// repl.MdocSession$App22$.<clinit>(can-catch.md:555),
// repl.MdocSession$App20$.<clinit>(can-catch.md:538),
// repl.MdocSession$App18$.<clinit>(can-catch.md:506),
// repl.MdocSession$App16$.<clinit>(can-catch.md:483),
// repl.MdocSession$App14$.<clinit>(can-catch.md:426),
// repl.MdocSession$App12$.<clinit>(can-catch.md:346),
// repl.MdocSession$App10$.<clinit>(can-catch.md:280),
// repl.MdocSession$App8$.<clinit>(can-catch.md:223),
// repl.MdocSession$App6$.<clinit>(can-catch.md:143),
// repl.MdocSession$App4$.<clinit>(can-catch.md:77),
// repl.MdocSession$App2$.<clinit>(can-catch.md:60),
// repl.MdocSession$App0$.<clinit>(can-catch.md:28),
// repl.MdocSession$App.<init>(can-catch.md:5),
// repl.MdocSession$.app(can-catch.md:3),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:...
import monix.execution.Scheduler.Implicits.global
val result = fa.runSyncUnsafe()
// result: Either[MyError, Int] = Left(
// value = NonFatalThrowable(
// throwable = java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100]
// )
// )
result match {
case Right(b) =>
println(s"Result is $b")
case Left(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#

import cats.data.EitherT
import monix.eval._
import effectie.monix._
val fa = CanCatch[Task].catchNonFatalEitherT(
EitherT(Task((throw new RuntimeException("Something's wrong!")): Either[Throwable, Int]))
)(identity)
// fa: EitherT[Task, Throwable, Int] = EitherT(
// value = Map(
// source = Map(
// source = FlatMap(
// source = Eval(thunk = <function0>),
// f = <function1>,
// trace = null
// ),
// f = effectie.monix.CanCatch$$anon$1$$Lambda$11212/0x000000010362c840@5fe1981a,
// trace = StackTrace(
// stackTrace = List(
// monix.eval.internal.TaskTracing$.buildFrame(TaskTracing.scala:52),
// monix.eval.internal.TaskTracing$.buildCachedFrame(TaskTracing.scala:43),
// monix.eval.internal.TaskTracing$.cached(TaskTracing.scala:38),
// monix.eval.Task.map(Task.scala:2027),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:32),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:28),
// repl.MdocSession$App0$.<clinit>(can-catch.md:19),
// repl.MdocSession$App.<init>(can-catch.md:5),
// repl.MdocSession$.app(can-catch.md:3),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withErr(Console.scala:193),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withOut(Console.scala:164),
// mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:88),
// mdoc.internal.markdown.MarkdownBuilder$.buildDocument(MarkdownBuilder.scala:44),
// mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:185),
// mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:152),
// mdoc.internal.markdown.Processor.processDocument(Processor.scala:52),
// mdoc.internal.markdown.Markdown$.toMarkdown(Markdown.scala:131),
// mdoc.internal.cli.MainOps.handleMarkdown(MainOps.scala:82),
// mdoc.internal.cli.MainOps.handleFile(MainOps.scala:110),
// mdoc.internal.cli.MainOps.$anonfun$generateCompleteSite$1(MainOps.scala:156),
// scala.collection.LinearSeqOps.foldLeft(LinearSeq.scala:169),
// ...
import monix.execution.Scheduler.Implicits.global
fa.value.runSyncUnsafe()
// res37: Either[Throwable, Int] = Left(
// value = java.lang.RuntimeException: Something's wrong!
// )

Happy Path Example#

import cats._
import cats.syntax.all._
import cats.data.EitherT
import monix.eval._
import effectie.monix._
import effectie.monix.Effectful._
import effectie.monix.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): Either[MyError, Int] =
if (n === 0)
MyError.divideByZero.asLeft[Int]
else
(100 / n).asRight[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[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
CanCatch[F].catchNonFatalEitherT(
for {
b <- EitherT(pureOf(divide100By(n)))
c <- eitherTRight[MyError](doSomethingBad(b))
} yield c
)(MyError.nonFatalThrowable).value
val fa = doSomething[Task](1)
// fa: Task[Either[MyError, Int]] = Map(
// source = Map(
// source = FlatMap(
// source = FlatMap(
// source = Now(value = Right(value = 100)),
// f = cats.data.EitherT$$Lambda$10991/0x0000000102bae840@10a9458a,
// trace = StackTrace(
// stackTrace = List(
// monix.eval.internal.TaskTracing$.buildFrame(TaskTracing.scala:52),
// monix.eval.internal.TaskTracing$.buildCachedFrame(TaskTracing.scala:43),
// monix.eval.internal.TaskTracing$.cached(TaskTracing.scala:38),
// monix.eval.Task.flatMap(Task.scala:1792),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:39),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:33),
// cats.data.EitherT.flatMap(EitherT.scala:403),
// repl.MdocSession$App42$$anonfun$doSomething$25.apply(can-catch.md:1169),
// repl.MdocSession$App42$$anonfun$doSomething$25.apply(can-catch.md:1169),
// effectie.monix.CanCatch.$anonfun$catchNonFatalEitherT$1(CanCatch.scala:22),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:32),
// effectie.monix.CanCatch$$anon$1.catchNonFatalEither(CanCatch.scala:37),
// effectie.monix.CanCatch$$anon$1.catchNonFatalEither(CanCatch.scala:28),
// effectie.monix.CanCatch.catchNonFatalEitherT(CanCatch.scala:22),
// effectie.monix.CanCatch.catchNonFatalEitherT$(CanCatch.scala:19),
// effectie.monix.CanCatch$$anon$1.catchNonFatalEitherT(CanCatch.scala:28),
// repl.MdocSession$App42$.doSomething(can-catch.md:1172),
// repl.MdocSession$App42$.<clinit>(can-catch.md:1175),
// repl.MdocSession$App40$.<clinit>(can-catch.md:1109),
// repl.MdocSession$App38$.<clinit>(can-catch.md:1086),
// repl.MdocSession$App36$.<clinit>(can-catch.md:1051),
// repl.MdocSession$App34$.<clinit>(can-catch.md:1025),
// repl.MdocSession$App32$.<clinit>(can-catch.md:957),
// repl.MdocSession$App30$.<clinit>(can-catch.md:867),
// repl.MdocSession$App28$.<clinit>(can-catch.md:790),
// repl.MdocSession$App26$.<clinit>(can-catch.md:722),
// repl.MdocSession$App24$.<clinit>(can-catch.md:632),
// repl.MdocSession$App22$.<clinit>(can-catch.md:555),
// repl.MdocSession$App20$.<clinit>(can-catch.md:538),
// repl.MdocSession$App18$.<clinit>(can-catch.md:506),
// repl.MdocSession$App16$.<clinit>(can-catch.md:483),
// repl.MdocSession$App14$.<clinit>(can-catch.md:426),
// ...
import monix.execution.Scheduler.Implicits.global
val result = fa.runSyncUnsafe()
// result: Either[MyError, Int] = Right(value = 200)
result match {
case Right(b) =>
println(s"Result is $b")
case Left(a) =>
println(s"Result: Failed with $a")
}
// Result is 200

Unhappy Path Example#

import cats._
import cats.data.EitherT
import cats.syntax.all._
import monix.eval._
import effectie.monix._
import effectie.monix.EitherTSupport._
import effectie.monix.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): Either[MyError, Int] =
if (n === 0)
MyError.divideByZero.asLeft[Int]
else
(100 / n).asRight[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[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
CanCatch[F].catchNonFatalEitherT(
for {
b <- EitherT(pureOf(divide100By(n)))
c <- eitherTRight[MyError](doSomethingBad(b))
} yield c
)(MyError.nonFatalThrowable).value
val fa = doSomething[Task](-1)
// fa: Task[Either[MyError, Int]] = Map(
// source = Map(
// source = FlatMap(
// source = FlatMap(
// source = Now(value = Right(value = -100)),
// f = cats.data.EitherT$$Lambda$10991/0x0000000102bae840@347a1b1f,
// trace = StackTrace(
// stackTrace = List(
// monix.eval.internal.TaskTracing$.buildFrame(TaskTracing.scala:52),
// monix.eval.internal.TaskTracing$.buildCachedFrame(TaskTracing.scala:43),
// monix.eval.internal.TaskTracing$.cached(TaskTracing.scala:38),
// monix.eval.Task.flatMap(Task.scala:1792),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:39),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:33),
// cats.data.EitherT.flatMap(EitherT.scala:403),
// repl.MdocSession$App42$$anonfun$doSomething$25.apply(can-catch.md:1169),
// repl.MdocSession$App42$$anonfun$doSomething$25.apply(can-catch.md:1169),
// effectie.monix.CanCatch.$anonfun$catchNonFatalEitherT$1(CanCatch.scala:22),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:32),
// effectie.monix.CanCatch$$anon$1.catchNonFatalEither(CanCatch.scala:37),
// effectie.monix.CanCatch$$anon$1.catchNonFatalEither(CanCatch.scala:28),
// effectie.monix.CanCatch.catchNonFatalEitherT(CanCatch.scala:22),
// effectie.monix.CanCatch.catchNonFatalEitherT$(CanCatch.scala:19),
// effectie.monix.CanCatch$$anon$1.catchNonFatalEitherT(CanCatch.scala:28),
// repl.MdocSession$App42$.doSomething(can-catch.md:1172),
// repl.MdocSession$App42$.<clinit>(can-catch.md:1175),
// repl.MdocSession$App40$.<clinit>(can-catch.md:1109),
// repl.MdocSession$App38$.<clinit>(can-catch.md:1086),
// repl.MdocSession$App36$.<clinit>(can-catch.md:1051),
// repl.MdocSession$App34$.<clinit>(can-catch.md:1025),
// repl.MdocSession$App32$.<clinit>(can-catch.md:957),
// repl.MdocSession$App30$.<clinit>(can-catch.md:867),
// repl.MdocSession$App28$.<clinit>(can-catch.md:790),
// repl.MdocSession$App26$.<clinit>(can-catch.md:722),
// repl.MdocSession$App24$.<clinit>(can-catch.md:632),
// repl.MdocSession$App22$.<clinit>(can-catch.md:555),
// repl.MdocSession$App20$.<clinit>(can-catch.md:538),
// repl.MdocSession$App18$.<clinit>(can-catch.md:506),
// repl.MdocSession$App16$.<clinit>(can-catch.md:483),
// repl.MdocSession$App14$.<clinit>(can-catch.md:426),
// ...
import monix.execution.Scheduler.Implicits.global
val result = fa.runSyncUnsafe()
// result: Either[MyError, Int] = Left(
// value = NonFatalThrowable(
// throwable = java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100]
// )
// )
result match {
case Right(b) =>
println(s"Result is $b")
case Left(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[Either[A, B]].

How to Use#

import monix.eval._
import effectie.monix.Catching._
val fa = catchNonFatal(
Task(throw new RuntimeException("Something's wrong!"))
)(identity)
// fa: Task[Either[Throwable, Nothing]] = Map(
// source = FlatMap(
// source = Eval(thunk = <function0>),
// f = <function1>,
// trace = null
// ),
// f = effectie.monix.CanCatch$$anon$1$$Lambda$11212/0x000000010362c840@f1b29cb,
// trace = StackTrace(
// stackTrace = List(
// monix.eval.internal.TaskTracing$.buildFrame(TaskTracing.scala:52),
// monix.eval.internal.TaskTracing$.buildCachedFrame(TaskTracing.scala:43),
// monix.eval.internal.TaskTracing$.cached(TaskTracing.scala:38),
// monix.eval.Task.map(Task.scala:2027),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:32),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:28),
// repl.MdocSession$App0$.<clinit>(can-catch.md:19),
// repl.MdocSession$App.<init>(can-catch.md:5),
// repl.MdocSession$.app(can-catch.md:3),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withErr(Console.scala:193),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withOut(Console.scala:164),
// mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:88),
// mdoc.internal.markdown.MarkdownBuilder$.buildDocument(MarkdownBuilder.scala:44),
// mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:185),
// mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:152),
// mdoc.internal.markdown.Processor.processDocument(Processor.scala:52),
// mdoc.internal.markdown.Markdown$.toMarkdown(Markdown.scala:131),
// mdoc.internal.cli.MainOps.handleMarkdown(MainOps.scala:82),
// mdoc.internal.cli.MainOps.handleFile(MainOps.scala:110),
// mdoc.internal.cli.MainOps.$anonfun$generateCompleteSite$1(MainOps.scala:156),
// scala.collection.LinearSeqOps.foldLeft(LinearSeq.scala:169),
// scala.collection.LinearSeqOps.foldLeft$(LinearSeq.scala:165),
// scala.collection.immutable.List.foldLeft(List.scala:79),
// mdoc.internal.cli.MainOps.generateCompleteSite(MainOps.scala:155),
// mdoc.internal.cli.MainOps.run(MainOps.scala:177),
// mdoc.internal.cli.MainOps$.process(MainOps.scala:269),
// mdoc.Main$.process(Main.scala:26),
// mdoc.Main$.process(Main.scala:21),
// mdoc.Main$.main(Main.scala:16),
// ...
import monix.execution.Scheduler.Implicits.global
fa.runSyncUnsafe()
// res55: Either[Throwable, Nothing] = Left(
// value = java.lang.RuntimeException: Something's wrong!
// )

Happy Path Example#

import cats._
import cats.syntax.all._
import monix.eval._
import effectie.monix._
import effectie.monix.Effectful._
import effectie.monix.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[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
catchNonFatal(
for {
a <- pureOf(n + 100)
b <- effectOf(doSomethingBad(a))
} yield b
)(MyError.nonFatalThrowable)
val fa = doSomething[Task](1)
// fa: Task[Either[MyError, Int]] = Map(
// source = FlatMap(
// source = FlatMap(
// source = Now(value = 101),
// f = <function1>,
// trace = StackTrace(
// stackTrace = List(
// monix.eval.internal.TaskTracing$.buildFrame(TaskTracing.scala:52),
// monix.eval.internal.TaskTracing$.buildCachedFrame(TaskTracing.scala:43),
// monix.eval.internal.TaskTracing$.cached(TaskTracing.scala:38),
// monix.eval.Task.flatMap(Task.scala:1792),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:39),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:33),
// cats.FlatMap$Ops.flatMap(FlatMap.scala:229),
// cats.FlatMap$Ops.flatMap$(FlatMap.scala:229),
// cats.FlatMap$ToFlatMapOps$$anon$2.flatMap(FlatMap.scala:243),
// repl.MdocSession$App60$$anonfun$doSomething$37.apply(can-catch.md:1733),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:32),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:28),
// effectie.monix.Catching$CurriedCanCatch2$.apply$extension(Catching.scala:45),
// repl.MdocSession$App60$.doSomething(can-catch.md:1736),
// repl.MdocSession$App60$.<clinit>(can-catch.md:1739),
// repl.MdocSession$App58$.<clinit>(can-catch.md:1687),
// repl.MdocSession$App56$.<clinit>(can-catch.md:1670),
// repl.MdocSession$App54$.<clinit>(can-catch.md:1638),
// repl.MdocSession$App52$.<clinit>(can-catch.md:1615),
// repl.MdocSession$App50$.<clinit>(can-catch.md:1541),
// repl.MdocSession$App48$.<clinit>(can-catch.md:1445),
// repl.MdocSession$App46$.<clinit>(can-catch.md:1362),
// repl.MdocSession$App44$.<clinit>(can-catch.md:1288),
// repl.MdocSession$App42$.<clinit>(can-catch.md:1192),
// repl.MdocSession$App40$.<clinit>(can-catch.md:1109),
// repl.MdocSession$App38$.<clinit>(can-catch.md:1086),
// repl.MdocSession$App36$.<clinit>(can-catch.md:1051),
// repl.MdocSession$App34$.<clinit>(can-catch.md:1025),
// repl.MdocSession$App32$.<clinit>(can-catch.md:957),
// repl.MdocSession$App30$.<clinit>(can-catch.md:867),
// repl.MdocSession$App28$.<clinit>(can-catch.md:790),
// repl.MdocSession$App26$.<clinit>(can-catch.md:722),
// repl.MdocSession$App24$.<clinit>(can-catch.md:632),
// repl.MdocSession$App22$.<clinit>(can-catch.md:555),
// repl.MdocSession$App20$.<clinit>(can-catch.md:538),
// repl.MdocSession$App18$.<clinit>(can-catch.md:506),
// repl.MdocSession$App16$.<clinit>(can-catch.md:483),
// ...
import monix.execution.Scheduler.Implicits.global
val result = fa.runSyncUnsafe()
// result: Either[MyError, Int] = Right(value = 202)
result match {
case Right(b) =>
println(s"Result is $b")
case Left(MyError.NonFatalThrowable(a)) =>
println(s"Result: Failed with $a")
}
// Result is 202

Unhappy Path Example#

import cats._
import cats.syntax.all._
import monix.eval._
import effectie.monix._
import effectie.monix.Effectful._
import effectie.monix.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[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
catchNonFatal(
for {
a <- pureOf(n + 100)
b <- effectOf(doSomethingBad(a))
} yield b
)(MyError.nonFatalThrowable)
val fa = doSomething[Task](-101)
// fa: Task[Either[MyError, Int]] = Map(
// source = FlatMap(
// source = FlatMap(
// source = Now(value = -1),
// f = <function1>,
// trace = StackTrace(
// stackTrace = List(
// monix.eval.internal.TaskTracing$.buildFrame(TaskTracing.scala:52),
// monix.eval.internal.TaskTracing$.buildCachedFrame(TaskTracing.scala:43),
// monix.eval.internal.TaskTracing$.cached(TaskTracing.scala:38),
// monix.eval.Task.flatMap(Task.scala:1792),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:39),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:33),
// cats.FlatMap$Ops.flatMap(FlatMap.scala:229),
// cats.FlatMap$Ops.flatMap$(FlatMap.scala:229),
// cats.FlatMap$ToFlatMapOps$$anon$2.flatMap(FlatMap.scala:243),
// repl.MdocSession$App66$$anonfun$doSomething$43.apply(can-catch.md:1946),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:32),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:28),
// effectie.monix.Catching$CurriedCanCatch2$.apply$extension(Catching.scala:45),
// repl.MdocSession$App66$.doSomething(can-catch.md:1949),
// repl.MdocSession$App66$.<clinit>(can-catch.md:1952),
// repl.MdocSession$App64$.<clinit>(can-catch.md:1900),
// repl.MdocSession$App62$.<clinit>(can-catch.md:1840),
// repl.MdocSession$App60$.<clinit>(can-catch.md:1756),
// repl.MdocSession$App58$.<clinit>(can-catch.md:1687),
// repl.MdocSession$App56$.<clinit>(can-catch.md:1670),
// repl.MdocSession$App54$.<clinit>(can-catch.md:1638),
// repl.MdocSession$App52$.<clinit>(can-catch.md:1615),
// repl.MdocSession$App50$.<clinit>(can-catch.md:1541),
// repl.MdocSession$App48$.<clinit>(can-catch.md:1445),
// repl.MdocSession$App46$.<clinit>(can-catch.md:1362),
// repl.MdocSession$App44$.<clinit>(can-catch.md:1288),
// repl.MdocSession$App42$.<clinit>(can-catch.md:1192),
// repl.MdocSession$App40$.<clinit>(can-catch.md:1109),
// repl.MdocSession$App38$.<clinit>(can-catch.md:1086),
// repl.MdocSession$App36$.<clinit>(can-catch.md:1051),
// repl.MdocSession$App34$.<clinit>(can-catch.md:1025),
// repl.MdocSession$App32$.<clinit>(can-catch.md:957),
// repl.MdocSession$App30$.<clinit>(can-catch.md:867),
// repl.MdocSession$App28$.<clinit>(can-catch.md:790),
// repl.MdocSession$App26$.<clinit>(can-catch.md:722),
// repl.MdocSession$App24$.<clinit>(can-catch.md:632),
// repl.MdocSession$App22$.<clinit>(can-catch.md:555),
// ...
import monix.execution.Scheduler.Implicits.global
val result = fa.runSyncUnsafe()
// result: Either[MyError, Int] = Left(
// value = NonFatalThrowable(
// throwable = java.lang.IllegalArgumentException: n cannot be a negative number. [n: -1]
// )
// )
result match {
case Right(b) =>
println(s"Result is $b")
case Left(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[Either[A, B]] and returns F[Either[A, B]].

How to Use#

import monix.eval._
import effectie.monix.Catching._
val fa = catchNonFatalEither(
Task((throw new RuntimeException("Something's wrong!")): Either[Throwable, Int])
)(identity)
// fa: Task[Either[Throwable, Int]] = Map(
// source = Map(
// source = FlatMap(
// source = Eval(thunk = <function0>),
// f = <function1>,
// trace = null
// ),
// f = effectie.monix.CanCatch$$anon$1$$Lambda$11212/0x000000010362c840@6e521d76,
// trace = StackTrace(
// stackTrace = List(
// monix.eval.internal.TaskTracing$.buildFrame(TaskTracing.scala:52),
// monix.eval.internal.TaskTracing$.buildCachedFrame(TaskTracing.scala:43),
// monix.eval.internal.TaskTracing$.cached(TaskTracing.scala:38),
// monix.eval.Task.map(Task.scala:2027),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:32),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:28),
// repl.MdocSession$App0$.<clinit>(can-catch.md:19),
// repl.MdocSession$App.<init>(can-catch.md:5),
// repl.MdocSession$.app(can-catch.md:3),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withErr(Console.scala:193),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withOut(Console.scala:164),
// mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:88),
// mdoc.internal.markdown.MarkdownBuilder$.buildDocument(MarkdownBuilder.scala:44),
// mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:185),
// mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:152),
// mdoc.internal.markdown.Processor.processDocument(Processor.scala:52),
// mdoc.internal.markdown.Markdown$.toMarkdown(Markdown.scala:131),
// mdoc.internal.cli.MainOps.handleMarkdown(MainOps.scala:82),
// mdoc.internal.cli.MainOps.handleFile(MainOps.scala:110),
// mdoc.internal.cli.MainOps.$anonfun$generateCompleteSite$1(MainOps.scala:156),
// scala.collection.LinearSeqOps.foldLeft(LinearSeq.scala:169),
// scala.collection.LinearSeqOps.foldLeft$(LinearSeq.scala:165),
// scala.collection.immutable.List.foldLeft(List.scala:79),
// mdoc.internal.cli.MainOps.generateCompleteSite(MainOps.scala:155),
// mdoc.internal.cli.MainOps.run(MainOps.scala:177),
// ...
import monix.execution.Scheduler.Implicits.global
fa.runSyncUnsafe()
// res73: Either[Throwable, Int] = Left(
// value = java.lang.RuntimeException: Something's wrong!
// )

Happy Path Example#

import cats._
import cats.syntax.all._
import monix.eval._
import effectie.monix._
import effectie.monix.Effectful._
import effectie.monix.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): Either[MyError, Int] =
if (n === 0)
MyError.divideByZero.asLeft[Int]
else
(100 / n).asRight[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[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
catchNonFatalEither(
for {
aOrB <- pureOf(divide100By(n))
c <- effectOf(aOrB.map(b => doSomethingBad(b)))
} yield c
)(MyError.nonFatalThrowable)
val fa = doSomething[Task](1)
// fa: Task[Either[MyError, Int]] = Map(
// source = Map(
// source = FlatMap(
// source = FlatMap(
// source = Now(value = Right(value = 100)),
// f = <function1>,
// trace = StackTrace(
// stackTrace = List(
// monix.eval.internal.TaskTracing$.buildFrame(TaskTracing.scala:52),
// monix.eval.internal.TaskTracing$.buildCachedFrame(TaskTracing.scala:43),
// monix.eval.internal.TaskTracing$.cached(TaskTracing.scala:38),
// monix.eval.Task.flatMap(Task.scala:1792),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:39),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:33),
// cats.FlatMap$Ops.flatMap(FlatMap.scala:229),
// cats.FlatMap$Ops.flatMap$(FlatMap.scala:229),
// cats.FlatMap$ToFlatMapOps$$anon$2.flatMap(FlatMap.scala:243),
// repl.MdocSession$App78$$anonfun$doSomething$49.apply(can-catch.md:2241),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:32),
// effectie.monix.CanCatch$$anon$1.catchNonFatalEither(CanCatch.scala:37),
// effectie.monix.CanCatch$$anon$1.catchNonFatalEither(CanCatch.scala:28),
// effectie.monix.Catching$CurriedCanCatchEither2$.apply$extension(Catching.scala:74),
// repl.MdocSession$App78$.doSomething(can-catch.md:2244),
// repl.MdocSession$App78$.<clinit>(can-catch.md:2247),
// repl.MdocSession$App76$.<clinit>(can-catch.md:2184),
// repl.MdocSession$App74$.<clinit>(can-catch.md:2167),
// repl.MdocSession$App72$.<clinit>(can-catch.md:2135),
// repl.MdocSession$App70$.<clinit>(can-catch.md:2112),
// repl.MdocSession$App68$.<clinit>(can-catch.md:2052),
// repl.MdocSession$App66$.<clinit>(can-catch.md:1969),
// repl.MdocSession$App64$.<clinit>(can-catch.md:1900),
// repl.MdocSession$App62$.<clinit>(can-catch.md:1840),
// repl.MdocSession$App60$.<clinit>(can-catch.md:1756),
// repl.MdocSession$App58$.<clinit>(can-catch.md:1687),
// repl.MdocSession$App56$.<clinit>(can-catch.md:1670),
// repl.MdocSession$App54$.<clinit>(can-catch.md:1638),
// repl.MdocSession$App52$.<clinit>(can-catch.md:1615),
// repl.MdocSession$App50$.<clinit>(can-catch.md:1541),
// repl.MdocSession$App48$.<clinit>(can-catch.md:1445),
// repl.MdocSession$App46$.<clinit>(can-catch.md:1362),
// repl.MdocSession$App44$.<clinit>(can-catch.md:1288),
// repl.MdocSession$App42$.<clinit>(can-catch.md:1192),
// ...
import monix.execution.Scheduler.Implicits.global
val result = fa.runSyncUnsafe()
// result: Either[MyError, Int] = Right(value = 200)
result match {
case Right(b) =>
println(s"Result is $b")
case Left(a) =>
println(s"Result: Failed with $a")
}
// Result is 200

Unhappy Path Example#

import cats._
import cats.syntax.all._
import monix.eval._
import effectie.monix._
import effectie.monix.Effectful._
import effectie.monix.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): Either[MyError, Int] =
if (n === 0)
MyError.divideByZero.asLeft[Int]
else
(100 / n).asRight[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[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
catchNonFatalEither(
for {
aOrB <- pureOf(divide100By(n))
c <- effectOf(aOrB.map(b => doSomethingBad(b)))
} yield c
)(MyError.nonFatalThrowable)
val fa = doSomething[Task](-1)
// fa: Task[Either[MyError, Int]] = Map(
// source = Map(
// source = FlatMap(
// source = FlatMap(
// source = Now(value = Right(value = -100)),
// f = <function1>,
// trace = StackTrace(
// stackTrace = List(
// monix.eval.internal.TaskTracing$.buildFrame(TaskTracing.scala:52),
// monix.eval.internal.TaskTracing$.buildCachedFrame(TaskTracing.scala:43),
// monix.eval.internal.TaskTracing$.cached(TaskTracing.scala:38),
// monix.eval.Task.flatMap(Task.scala:1792),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:39),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:33),
// cats.FlatMap$Ops.flatMap(FlatMap.scala:229),
// cats.FlatMap$Ops.flatMap$(FlatMap.scala:229),
// cats.FlatMap$ToFlatMapOps$$anon$2.flatMap(FlatMap.scala:243),
// repl.MdocSession$App84$$anonfun$doSomething$55.apply(can-catch.md:2485),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:32),
// effectie.monix.CanCatch$$anon$1.catchNonFatalEither(CanCatch.scala:37),
// effectie.monix.CanCatch$$anon$1.catchNonFatalEither(CanCatch.scala:28),
// effectie.monix.Catching$CurriedCanCatchEither2$.apply$extension(Catching.scala:74),
// repl.MdocSession$App84$.doSomething(can-catch.md:2488),
// repl.MdocSession$App84$.<clinit>(can-catch.md:2491),
// repl.MdocSession$App82$.<clinit>(can-catch.md:2428),
// repl.MdocSession$App80$.<clinit>(can-catch.md:2357),
// repl.MdocSession$App78$.<clinit>(can-catch.md:2264),
// repl.MdocSession$App76$.<clinit>(can-catch.md:2184),
// repl.MdocSession$App74$.<clinit>(can-catch.md:2167),
// repl.MdocSession$App72$.<clinit>(can-catch.md:2135),
// repl.MdocSession$App70$.<clinit>(can-catch.md:2112),
// repl.MdocSession$App68$.<clinit>(can-catch.md:2052),
// repl.MdocSession$App66$.<clinit>(can-catch.md:1969),
// repl.MdocSession$App64$.<clinit>(can-catch.md:1900),
// repl.MdocSession$App62$.<clinit>(can-catch.md:1840),
// repl.MdocSession$App60$.<clinit>(can-catch.md:1756),
// repl.MdocSession$App58$.<clinit>(can-catch.md:1687),
// repl.MdocSession$App56$.<clinit>(can-catch.md:1670),
// repl.MdocSession$App54$.<clinit>(can-catch.md:1638),
// repl.MdocSession$App52$.<clinit>(can-catch.md:1615),
// repl.MdocSession$App50$.<clinit>(can-catch.md:1541),
// repl.MdocSession$App48$.<clinit>(can-catch.md:1445),
// ...
import monix.execution.Scheduler.Implicits.global
val result = fa.runSyncUnsafe()
// result: Either[MyError, Int] = Left(
// value = NonFatalThrowable(
// throwable = java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100]
// )
// )
result match {
case Right(b) =>
println(s"Result is $b")
case Left(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#

import cats.data.EitherT
import monix.eval._
import effectie.monix.Catching._
val fa = catchNonFatalEitherT[Task](
EitherT(Task((throw new RuntimeException("Something's wrong!")): Either[Throwable, Int]))
)(identity)
// fa: EitherT[Task, Throwable, Int] = EitherT(
// value = Map(
// source = Map(
// source = FlatMap(
// source = Eval(thunk = <function0>),
// f = <function1>,
// trace = null
// ),
// f = effectie.monix.CanCatch$$anon$1$$Lambda$11212/0x000000010362c840@5d4dd8c6,
// trace = StackTrace(
// stackTrace = List(
// monix.eval.internal.TaskTracing$.buildFrame(TaskTracing.scala:52),
// monix.eval.internal.TaskTracing$.buildCachedFrame(TaskTracing.scala:43),
// monix.eval.internal.TaskTracing$.cached(TaskTracing.scala:38),
// monix.eval.Task.map(Task.scala:2027),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:32),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:28),
// repl.MdocSession$App0$.<clinit>(can-catch.md:19),
// repl.MdocSession$App.<init>(can-catch.md:5),
// repl.MdocSession$.app(can-catch.md:3),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$2(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withErr(Console.scala:193),
// mdoc.internal.document.DocumentBuilder$$doc$.$anonfun$build$1(DocumentBuilder.scala:89),
// scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18),
// scala.util.DynamicVariable.withValue(DynamicVariable.scala:59),
// scala.Console$.withOut(Console.scala:164),
// mdoc.internal.document.DocumentBuilder$$doc$.build(DocumentBuilder.scala:88),
// mdoc.internal.markdown.MarkdownBuilder$.buildDocument(MarkdownBuilder.scala:44),
// mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:185),
// mdoc.internal.markdown.Processor.processScalaInputs(Processor.scala:152),
// mdoc.internal.markdown.Processor.processDocument(Processor.scala:52),
// mdoc.internal.markdown.Markdown$.toMarkdown(Markdown.scala:131),
// mdoc.internal.cli.MainOps.handleMarkdown(MainOps.scala:82),
// mdoc.internal.cli.MainOps.handleFile(MainOps.scala:110),
// mdoc.internal.cli.MainOps.$anonfun$generateCompleteSite$1(MainOps.scala:156),
// scala.collection.LinearSeqOps.foldLeft(LinearSeq.scala:169),
// ...
import monix.execution.Scheduler.Implicits.global
fa.value.runSyncUnsafe()
// res91: Either[Throwable, Int] = Left(
// value = java.lang.RuntimeException: Something's wrong!
// )

Happy Path Example#

import cats._
import cats.syntax.all._
import cats.data.EitherT
import monix.eval._
import effectie.monix._
import effectie.monix.Effectful._
import effectie.monix.Catching._
import effectie.monix.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): Either[MyError, Int] =
if (n === 0)
MyError.divideByZero.asLeft[Int]
else
(100 / n).asRight[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[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
catchNonFatalEitherT(
for {
b <- EitherT(pureOf(divide100By(n)))
c <- eitherTRight[MyError](doSomethingBad(b))
} yield c
)(MyError.nonFatalThrowable).value
val fa = doSomething[Task](1)
// fa: Task[Either[MyError, Int]] = Map(
// source = Map(
// source = FlatMap(
// source = FlatMap(
// source = Now(value = Right(value = 100)),
// f = cats.data.EitherT$$Lambda$10991/0x0000000102bae840@79915d69,
// trace = StackTrace(
// stackTrace = List(
// monix.eval.internal.TaskTracing$.buildFrame(TaskTracing.scala:52),
// monix.eval.internal.TaskTracing$.buildCachedFrame(TaskTracing.scala:43),
// monix.eval.internal.TaskTracing$.cached(TaskTracing.scala:38),
// monix.eval.Task.flatMap(Task.scala:1792),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:39),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:33),
// cats.data.EitherT.flatMap(EitherT.scala:403),
// repl.MdocSession$App42$$anonfun$doSomething$25.apply(can-catch.md:1169),
// repl.MdocSession$App42$$anonfun$doSomething$25.apply(can-catch.md:1169),
// effectie.monix.CanCatch.$anonfun$catchNonFatalEitherT$1(CanCatch.scala:22),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:32),
// effectie.monix.CanCatch$$anon$1.catchNonFatalEither(CanCatch.scala:37),
// effectie.monix.CanCatch$$anon$1.catchNonFatalEither(CanCatch.scala:28),
// effectie.monix.CanCatch.catchNonFatalEitherT(CanCatch.scala:22),
// effectie.monix.CanCatch.catchNonFatalEitherT$(CanCatch.scala:19),
// effectie.monix.CanCatch$$anon$1.catchNonFatalEitherT(CanCatch.scala:28),
// repl.MdocSession$App42$.doSomething(can-catch.md:1172),
// repl.MdocSession$App42$.<clinit>(can-catch.md:1175),
// repl.MdocSession$App40$.<clinit>(can-catch.md:1109),
// repl.MdocSession$App38$.<clinit>(can-catch.md:1086),
// repl.MdocSession$App36$.<clinit>(can-catch.md:1051),
// repl.MdocSession$App34$.<clinit>(can-catch.md:1025),
// repl.MdocSession$App32$.<clinit>(can-catch.md:957),
// repl.MdocSession$App30$.<clinit>(can-catch.md:867),
// repl.MdocSession$App28$.<clinit>(can-catch.md:790),
// repl.MdocSession$App26$.<clinit>(can-catch.md:722),
// repl.MdocSession$App24$.<clinit>(can-catch.md:632),
// repl.MdocSession$App22$.<clinit>(can-catch.md:555),
// repl.MdocSession$App20$.<clinit>(can-catch.md:538),
// repl.MdocSession$App18$.<clinit>(can-catch.md:506),
// repl.MdocSession$App16$.<clinit>(can-catch.md:483),
// repl.MdocSession$App14$.<clinit>(can-catch.md:426),
// ...
import monix.execution.Scheduler.Implicits.global
val result = fa.runSyncUnsafe()
// result: Either[MyError, Int] = Right(value = 200)
result match {
case Right(b) =>
println(s"Result is $b")
case Left(a) =>
println(s"Result: Failed with $a")
}
// Result is 200

Unhappy Path Example#

import cats._
import cats.data.EitherT
import cats.syntax.all._
import monix.eval._
import effectie.monix._
import effectie.monix.Effectful._
import effectie.monix.Catching._
import effectie.monix.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): Either[MyError, Int] =
if (n === 0)
MyError.divideByZero.asLeft[Int]
else
(100 / n).asRight[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[_]: EffectConstructor: CanCatch: Monad](
n: Int
): F[Either[MyError, Int]] =
catchNonFatalEitherT(
for {
b <- EitherT(pureOf(divide100By(n)))
c <- eitherTRight[MyError](doSomethingBad(b))
} yield c
)(MyError.nonFatalThrowable).value
val fa = doSomething[Task](-1)
// fa: Task[Either[MyError, Int]] = Map(
// source = Map(
// source = FlatMap(
// source = FlatMap(
// source = Now(value = Right(value = -100)),
// f = cats.data.EitherT$$Lambda$10991/0x0000000102bae840@21b12d9,
// trace = StackTrace(
// stackTrace = List(
// monix.eval.internal.TaskTracing$.buildFrame(TaskTracing.scala:52),
// monix.eval.internal.TaskTracing$.buildCachedFrame(TaskTracing.scala:43),
// monix.eval.internal.TaskTracing$.cached(TaskTracing.scala:38),
// monix.eval.Task.flatMap(Task.scala:1792),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:39),
// monix.eval.instances.CatsBaseForTask.flatMap(CatsBaseForTask.scala:33),
// cats.data.EitherT.flatMap(EitherT.scala:403),
// repl.MdocSession$App42$$anonfun$doSomething$25.apply(can-catch.md:1169),
// repl.MdocSession$App42$$anonfun$doSomething$25.apply(can-catch.md:1169),
// effectie.monix.CanCatch.$anonfun$catchNonFatalEitherT$1(CanCatch.scala:22),
// effectie.monix.CanCatch$$anon$1.catchNonFatal(CanCatch.scala:32),
// effectie.monix.CanCatch$$anon$1.catchNonFatalEither(CanCatch.scala:37),
// effectie.monix.CanCatch$$anon$1.catchNonFatalEither(CanCatch.scala:28),
// effectie.monix.CanCatch.catchNonFatalEitherT(CanCatch.scala:22),
// effectie.monix.CanCatch.catchNonFatalEitherT$(CanCatch.scala:19),
// effectie.monix.CanCatch$$anon$1.catchNonFatalEitherT(CanCatch.scala:28),
// repl.MdocSession$App42$.doSomething(can-catch.md:1172),
// repl.MdocSession$App42$.<clinit>(can-catch.md:1175),
// repl.MdocSession$App40$.<clinit>(can-catch.md:1109),
// repl.MdocSession$App38$.<clinit>(can-catch.md:1086),
// repl.MdocSession$App36$.<clinit>(can-catch.md:1051),
// repl.MdocSession$App34$.<clinit>(can-catch.md:1025),
// repl.MdocSession$App32$.<clinit>(can-catch.md:957),
// repl.MdocSession$App30$.<clinit>(can-catch.md:867),
// repl.MdocSession$App28$.<clinit>(can-catch.md:790),
// repl.MdocSession$App26$.<clinit>(can-catch.md:722),
// repl.MdocSession$App24$.<clinit>(can-catch.md:632),
// repl.MdocSession$App22$.<clinit>(can-catch.md:555),
// repl.MdocSession$App20$.<clinit>(can-catch.md:538),
// repl.MdocSession$App18$.<clinit>(can-catch.md:506),
// repl.MdocSession$App16$.<clinit>(can-catch.md:483),
// repl.MdocSession$App14$.<clinit>(can-catch.md:426),
// ...
import monix.execution.Scheduler.Implicits.global
val result = fa.runSyncUnsafe()
// result: Either[MyError, Int] = Left(
// value = NonFatalThrowable(
// throwable = java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100]
// )
// )
result match {
case Right(b) =>
println(s"Result is $b")
case Left(a) =>
println(s"Result: Failed with $a")
}
// Result: Failed with NonFatalThrowable(java.lang.IllegalArgumentException: n cannot be a negative number. [n: -100])