Skip to content

Commit

Permalink
Merge pull request #31 from rcardin/30-inline-fold-function
Browse files Browse the repository at this point in the history
inlined Raise functions
  • Loading branch information
rcardin authored May 3, 2024
2 parents f11e4e3 + ca9b97c commit f500e54
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 79 deletions.
18 changes: 3 additions & 15 deletions src/main/scala/in/rcard/raise4s/Builders.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,10 @@ import in.rcard.raise4s.Bind.value

import scala.util.{Failure, Success, Try}

private[raise4s] def _either[Error, A](block: Raise[Error] ?=> A): Either[Error, A] = {
private[raise4s] inline def _either[Error, A](inline block: Raise[Error] ?=> A): Either[Error, A] = {
Raise.fold(block, error => Left(error), value => Right(value))
}

@deprecated("Use the Raise.either method instead", "0.0.3")
def either[A, Error](block: Raise[Error] ?=> A): Either[Error, A] =
_either(block)

object RaiseEitherPredef:
extension [Error, A](either: Either[Error, A])(using r: Raise[Error])
@deprecated("Use the extension method 'value' defined in Bind scope instead", "0.0.5")
Expand All @@ -22,35 +18,27 @@ object RaiseOptionPredef:
@deprecated("Use the extension method 'value' defined in Bind scope instead", "0.0.5")
def bind(): A = option.value

private[raise4s] def _option[A](block: Raise[None.type] ?=> A): Option[A] = {
private[raise4s] inline def _option[A](inline block: Raise[None.type] ?=> A): Option[A] = {
Raise.fold(
block,
_ => None,
Some(_)
)
}

@deprecated("Use the Raise.option method instead", "0.0.3")
def option[A](block: Raise[None.type] ?=> A): Option[A] =
_option(block)

object RaiseTryPredef:
extension [A](tryValue: Try[A])(using tryRaise: Raise[Throwable])
@deprecated("Use the extension method 'value' defined in Bind scope instead", "0.0.5")
def bind(): A = tryValue.value

private[raise4s] def _asTry[A](block: Raise[Throwable] ?=> A): Try[A] = {
private[raise4s] inline def _asTry[A](inline block: Raise[Throwable] ?=> A): Try[A] = {
Raise.fold(
block,
Failure(_),
Success(_)
)
}

@deprecated("Use the Raise.asTry method instead", "0.0.3")
def asTry[A](block: Raise[Throwable] ?=> A): Try[A] =
_asTry(block)

object RaiseAnyPredef:
extension [A](value: A) def succeed: Raise[Nothing] ?=> A = { value }

Expand Down
33 changes: 0 additions & 33 deletions src/main/scala/in/rcard/raise4s/Fold.scala
Original file line number Diff line number Diff line change
@@ -1,38 +1,5 @@
package in.rcard.raise4s

import scala.util.control.NonFatal

private[raise4s] def _fold[Error, B, A](
block: Raise[Error] ?=> A,
catchBlock: (throwable: Throwable) => B,
recover: (error: Error) => B,
transform: (value: A) => B
) = {
given raise: Raise[Error] = new DefaultRaise

try transform(block)
catch
case Raised(error) => recover(error.asInstanceOf[Error])
case NonFatal(e) => catchBlock(e)
case e: Throwable => throw e
}

@deprecated("Use Raise.fold instead", "0.0.3")
def fold[A, B, Error](
block: Raise[Error] ?=> A,
catchBlock: (throwable: Throwable) => B,
recover: (error: Error) => B,
transform: (value: A) => B
): B =
_fold(block, catchBlock, recover, transform)

@deprecated("Use Raise.fold instead", "0.0.3")
def fold[A, B, Error](
block: Raise[Error] ?=> A,
recover: (error: Error) => B,
transform: (value: A) => B
): B = _fold(block, ex => throw ex, recover, transform)

private[raise4s] def _mapOrAccumulate[Error, A, B](iterable: Iterable[A])(
transform: Raise[Error] ?=> A => B
)(using r: Raise[List[Error]]): List[B] =
Expand Down
71 changes: 40 additions & 31 deletions src/main/scala/in/rcard/raise4s/Raise.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ object Raise {

extension [A](a: => A)
/** Extensions method version of the [[Raise.catching]] function.
*/
//noinspection NoTailRecursionAnnotation
*/
// noinspection NoTailRecursionAnnotation
@targetName("catchingThis")
def catching(catchBlock: Throwable => A): A = Raise.catching(() => a)(catchBlock)
inline def catching(inline 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.
*
* __Alternatives:__ Common ways to raise errors include: [[ensure]], [[ensureNotNull]], and
* [[RaiseEitherPredef.bind]]. Consider using them to make your code more concise and expressive.
* [[Bind.value]]. Consider using them to make your code more concise and expressive.
*
* __Handling raised errors:__ Refer to [[recover]]. <h2>Example</h2>
* {{{
Expand All @@ -51,7 +51,7 @@ object Raise {
* @tparam Error
* The type of the logical error
*/
def raise[Error](e: Error)(using raise: Raise[Error]): Nothing = raise.raise(e)
inline def raise[Error](e: Error)(using raise: Raise[Error]): Nothing = raise.raise(e)

/** Ensures that the `condition` is met; otherwise, [[Raise.raise]]s a logical failure of type
* `Error`.
Expand All @@ -77,7 +77,7 @@ object Raise {
* @tparam Error
* The type of the logical error
*/
def ensure[Error](condition: Boolean)(raise: => Error)(using r: Raise[Error]): Unit =
inline def ensure[Error](condition: Boolean)(raise: => Error)(using r: Raise[Error]): Unit =
if !condition then r.raise(raise)

/** Ensures that the `value` is not null; otherwise, [[Raise.raise]]s a logical failure of type
Expand Down Expand Up @@ -108,7 +108,7 @@ object Raise {
* @return
* The value if it is not null
*/
def ensureNotNull[B, Error](value: B)(raise: => Error)(using r: Raise[Error]): B =
inline def ensureNotNull[B, Error](value: B)(raise: => Error)(using r: Raise[Error]): B =
if value == null then r.raise(raise)
else value

Expand All @@ -134,8 +134,8 @@ object Raise {
* @return
* The result of the `block` or the fallback value
*/
def recover[Error, A](block: Raise[Error] ?=> A)(recover: Error => A): A =
fold(block, ex => throw ex, recover, identity)
inline def recover[Error, A](inline block: Raise[Error] ?=> A)(inline recover: Error => A): A =
Raise.fold(block, ex => throw ex, recover, identity)

/** Execute the [[Raise]] context function resulting in `A` or any _logical error_ of type
* `Error`, and `recover` by providing a transform `Error` into a fallback value of type `A`, or
Expand Down Expand Up @@ -166,12 +166,12 @@ object Raise {
* The result of the `block`, the fallback value from the `recover` function, or the fallback
* value from the `catchBlock` function
*/
def recover[Error, A](
block: Raise[Error] ?=> A,
recover: Error => A,
catchBlock: Throwable => A
inline def recover[Error, A](
inline block: Raise[Error] ?=> A,
inline recover: Error => A,
inline catchBlock: Throwable => A
): A =
fold(block, catchBlock, recover, identity)
Raise.fold(block, catchBlock, recover, identity)

/** Allows safely catching [[NonFatal]] exceptions without capturing exceptions like
* [[OutOfMemoryError]] or [[VirtualMachineError]], etc.
Expand All @@ -194,7 +194,7 @@ object Raise {
* @return
* The result of the `block` or the fallback value
*/
def catching[A](block: () => A)(catchBlock: Throwable => A): A =
inline def catching[A](inline block: () => A)(inline catchBlock: Throwable => A): A =
try block()
catch
case NonFatal(e) => catchBlock(e)
Expand Down Expand Up @@ -227,8 +227,8 @@ object Raise {
* @return
* The result of the `block`
*/
def withError[Error, OtherError, A](transform: OtherError => Error)(
block: Raise[OtherError] ?=> A
inline def withError[Error, OtherError, A](inline transform: OtherError => Error)(
inline block: Raise[OtherError] ?=> A
)(using r: Raise[Error]): A =
recover(block) { otherError => r.raise(transform(otherError)) }

Expand Down Expand Up @@ -267,12 +267,20 @@ object Raise {
* @tparam Error
* The type of the logical error that can be raised by the `block` lambda
*/
def fold[A, B, Error](
block: Raise[Error] ?=> A,
catchBlock: (throwable: Throwable) => B,
recover: (error: Error) => B,
transform: (value: A) => B
): B = _fold(block, catchBlock, recover, transform)
inline def fold[A, B, Error](
inline block: Raise[Error] ?=> A,
inline catchBlock: (throwable: Throwable) => B,
inline recover: (error: Error) => B,
inline transform: (value: A) => B
): B = {
given raise: Raise[Error] = new DefaultRaise

try transform(block)
catch
case Raised(error) => recover(error.asInstanceOf[Error])
case NonFatal(e) => catchBlock(e)
case e: Throwable => throw e
}

/** The most general way to execute a computation using [[Raise]]. Depending on the outcome of the
* `block`, one of the two continuations is run:
Expand Down Expand Up @@ -304,11 +312,12 @@ object Raise {
* @tparam Error
* The type of the logical error that can be raised by the `block` lambda
*/
def fold[A, B, Error](
block: Raise[Error] ?=> A,
recover: (error: Error) => B,
transform: (value: A) => B
): B = _fold(block, ex => throw ex, recover, transform)
//noinspection NoTailRecursionAnnotation
inline def fold[A, B, Error](
inline block: Raise[Error] ?=> A,
inline recover: (error: Error) => B,
inline transform: (value: A) => B
): B = Raise.fold(block, ex => throw ex, recover, transform)

/** Runs a computation `block` using [[Raise]], and return its outcome as [[Either]].
* - [[Right]] represents success,
Expand Down Expand Up @@ -341,7 +350,7 @@ object Raise {
* @return
* An [[Either]] representing the outcome of the computation
*/
def either[A, Error](block: Raise[Error] ?=> A): Either[Error, A] = _either(block)
inline def either[A, Error](inline block: Raise[Error] ?=> A): Either[Error, A] = _either(block)

/** Runs a computation `block` using [[Raise]], and return its outcome as [[Option]].
* - [[Some]] represents success,
Expand All @@ -367,7 +376,7 @@ object Raise {
* @return
* An [[Option]] representing the outcome of the computation
*/
def option[A](block: Raise[None.type] ?=> A): Option[A] = _option(block)
inline def option[A](inline block: Raise[None.type] ?=> A): Option[A] = _option(block)

/** Runs a computation `block` using [[Raise]], and return its outcome as [[Try]].
*
Expand All @@ -390,7 +399,7 @@ object Raise {
* @return
* An [[Try]] representing the outcome of the computation
*/
def asTry[A](block: Raise[Throwable] ?=> A): Try[A] = _asTry(block)
inline def asTry[A](inline block: Raise[Throwable] ?=> A): Try[A] = _asTry(block)

/** Accumulate the errors obtained by executing the `transform` over every element of `iterable`.
*
Expand Down

0 comments on commit f500e54

Please sign in to comment.