Skip to content

Commit 8609896

Browse files
authored
Merge pull request #34 from rcardin/33-create-a-run-function-returning-a-union-type-e-|-a
Create a run function returning a union type E | A
2 parents a7d9725 + 0b854d7 commit 8609896

File tree

4 files changed

+62
-1
lines changed

4 files changed

+62
-1
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,14 @@ The `fold` function “consumes” the context, creating a concrete instance of
104104

105105
There are other flavors of the `fold` function. So, please, be sure to check them in the documentation.
106106

107+
For those who are not interested in handling possible exceptions raised by a function, there is a more straightforward function available, called `run`:
108+
109+
```scala 3
110+
val maybeUser: Error | User = Raise.run {
111+
findUserById("42")
112+
}
113+
```
114+
107115
Please be aware that any exception thrown inside the `Raise[E]` context will bubble up and not be transformed automatically into a logical typed error. What if we want to convert the exception into a typed error? For example, we want to convert the `IllegalArgumentException` into a `UserNotFound`. Well, we can do it using a function called `catching`:
108116

109117
```scala 3

src/main/scala/in/rcard/raise4s/Raise.scala

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ object Raise {
312312
* @tparam Error
313313
* The type of the logical error that can be raised by the `block` lambda
314314
*/
315-
//noinspection NoTailRecursionAnnotation
315+
// noinspection NoTailRecursionAnnotation
316316
inline def fold[A, B, Error](
317317
inline block: Raise[Error] ?=> A,
318318
inline recover: (error: Error) => B,
@@ -999,4 +999,25 @@ object Raise {
999999
)(
10001000
block
10011001
)
1002+
1003+
/** Execute a block of code that can raise a logical error and return the result or the error as a
1004+
* union type `Error | A`.
1005+
*
1006+
* <h2>Example</h2>
1007+
* {{{
1008+
* val happyPathBlock: Int raises String = 42
1009+
* val result: String | Int = Runtime._run(happyPathBlock)
1010+
* result should be(42)
1011+
* }}}
1012+
*
1013+
* @param block
1014+
* The block of code to execute that can raise an a logical type error
1015+
* @tparam Error
1016+
* The type of the logical error that can be raised by the `block` lambda
1017+
* @tparam A
1018+
* The type of the result of the execution of `block` lambda
1019+
* @return
1020+
* The result of the execution of the `block` lambda or the logical error
1021+
*/
1022+
def run[Error, A](block: Raise[Error] ?=> A): Error | A = Runtime._run(block)
10021023
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package in.rcard.raise4s
2+
3+
object Runtime {
4+
5+
private[raise4s] def _run[Error, A](block: Raise[Error] ?=> A): Error | A =
6+
Raise.fold(block, identity, identity)
7+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package in.rcard.raise4s
2+
3+
import org.scalatest.flatspec.AnyFlatSpec
4+
import org.scalatest.matchers.should.Matchers
5+
6+
class RuntimeSpec extends AnyFlatSpec with Matchers {
7+
"Raise.run" should "return the happy path value is no error was risen" in {
8+
val happyPathBlock: Int raises String = 42
9+
val result: String | Int = Runtime._run(happyPathBlock)
10+
result should be(42)
11+
}
12+
13+
it should "return the error value if an error was risen" in {
14+
val errorBlock: Int raises String = Raise.raise("error")
15+
val result: String | Int = Runtime._run(errorBlock)
16+
result should be("error")
17+
}
18+
19+
it should "be transparent to any thrown exception" in {
20+
val exceptionBlock: Int raises String = throw new RuntimeException("error")
21+
assertThrows[RuntimeException] {
22+
Runtime._run(exceptionBlock)
23+
}
24+
}
25+
}

0 commit comments

Comments
 (0)