Skip to content

Commit

Permalink
Merge pull request #15 from rcardin/13-create-an-extension-version-of…
Browse files Browse the repository at this point in the history
…-the-raisecatching-function

Added the 'catching' function as an extension method.
  • Loading branch information
rcardin authored Apr 24, 2024
2 parents 45bcff6 + fa6812c commit d6cf227
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 0 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,14 @@ val maybeUser: Either[Error, User] =
})
```

There is also a version of the `catching` function defined as an extension method of any `A` type. The above code can be rewritten as follows:

```scala 3
findUserByIdWithEx("42").catching {
case _: IllegalArgumentException => Raise.raise(UserNotFound("42"))
}
```

We will see the `either` function in a moment. As we can see, there’s nothing special with the `catching` function. It just catches the exception and calls the catch lambda with the exception. The `catching` function lets the fatal exception bubble up.

It’s a different story if we want to recover or react to a typed error. In this case, we can use the `recover` function:
Expand Down
5 changes: 5 additions & 0 deletions src/main/scala/in/rcard/raise4s/Raise.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package in.rcard.raise4s

import scala.annotation.targetName
import scala.util.Try
import scala.util.control.{ControlThrowable, NoStackTrace, NonFatal}

Expand All @@ -19,6 +20,10 @@ infix type raises[R, Error] = Raise[Error] ?=> R
*/
object Raise {

extension [A](a: => A)
@targetName("catchingThis")
def catching(catchBlock: Throwable => A): A = Raise.catching(() => a, catchBlock)

/** Raises a _logical failure_ of type `Error`. This function behaves like a <em>return
* statement</em>, immediately short-circuiting and terminating the computation.
*
Expand Down
25 changes: 25 additions & 0 deletions src/test/scala/in/rcard/raise4s/RaiseSpec.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package in.rcard.raise4s

import in.rcard.raise4s.Raise.catching
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

Expand Down Expand Up @@ -140,4 +141,28 @@ class RaiseSpec extends AnyFlatSpec with Matchers {

actual should be(Left(5))
}

"catching as an extension method" should "return the value if no exception is thrown" in {
val actual = 42.catching { ex =>
43
}

actual should be(42)
}

it should "return the recovery value if an exception is thrown" in {
val actual = { throw new RuntimeException("error") }.catching { ex =>
43
}

actual should be(43)
}

it should "rethrow any fatal exception" in {
assertThrows[OutOfMemoryError] {
{ throw new OutOfMemoryError("error") }.catching { ex =>
43
}
}
}
}

0 comments on commit d6cf227

Please sign in to comment.