Materializes any sequenced exceptions into value space, where they may be handled.
Materializes any sequenced exceptions into value space, where they may be handled.
This is analogous to the catch
clause in try
/catch
, being
the inverse of SyncIO.raiseError
. Thus:
SyncIO.raiseError(ex).attempt.unsafeRunSync === Left(ex)
Returns a SyncIO
action that treats the source task as the
acquisition of a resource, which is then exploited by the use
function and then released
.
Returns a SyncIO
action that treats the source task as the
acquisition of a resource, which is then exploited by the use
function and then released
.
The bracket
operation is the equivalent of the
try {} catch {} finally {}
statements from mainstream languages.
The bracket
operation installs the necessary exception handler
to release the resource in the event of an exception being raised
during the computation.
If an exception is raised, then bracket
will re-raise the
exception after performing the release
.
NOTE on error handling: one big difference versus
try/finally
statements is that, in case both the release
function and the use
function throws, the error raised by use
gets signaled.
For example:
SyncIO("resource").bracket { _ => // use SyncIO.raiseError(new RuntimeException("Foo")) } { _ => // release SyncIO.raiseError(new RuntimeException("Bar")) }
In this case the error signaled downstream is "Foo"
, while the
"Bar"
error gets reported. This is consistent with the behavior
of Haskell's bracket
operation and NOT with try {} finally {}
from Scala, Java or JavaScript.
is a function that evaluates the resource yielded by
the source, yielding a result that will get generated by
the task returned by this bracket
function
is a function that gets called after use
terminates, either normally or in error, or if it gets
canceled, receiving as input the resource that needs to
be released
Returns a new SyncIO
task that treats the source task as the
acquisition of a resource, which is then exploited by the use
function and then released
, with the possibility of
distinguishing between normal termination and failure, such
that an appropriate release of resources can be executed.
Returns a new SyncIO
task that treats the source task as the
acquisition of a resource, which is then exploited by the use
function and then released
, with the possibility of
distinguishing between normal termination and failure, such
that an appropriate release of resources can be executed.
The bracketCase
operation is the equivalent of
try {} catch {} finally {}
statements from mainstream languages
when used for the acquisition and release of resources.
The bracketCase
operation installs the necessary exception handler
to release the resource in the event of an exception being raised
during the computation.
In comparison with the simpler bracket version, this one
allows the caller to differentiate between normal termination and
termination in error. Note SyncIO
does not support cancelation
so that exit case should be ignored.
is a function that evaluates the resource yielded by the source, yielding a result that will get generated by this function on evaluation
is a function that gets called after use
terminates, either normally or in error, receiving
as input the resource that needs that needs release,
along with the result of use
(error or successful result)
Monadic bind on SyncIO
, used for sequentially composing two SyncIO
actions, where the value produced by the first SyncIO
is passed as
input to a function producing the second SyncIO
action.
Monadic bind on SyncIO
, used for sequentially composing two SyncIO
actions, where the value produced by the first SyncIO
is passed as
input to a function producing the second SyncIO
action.
Due to this operation's signature, flatMap
forces a data
dependency between two SyncIO
actions, thus ensuring sequencing
(e.g. one action to be executed before another one).
Any exceptions thrown within the function will be caught and
sequenced in to the result SyncIO[B].
Executes the given finalizer
when the source is finished,
either in success or in error.
Executes the given finalizer
when the source is finished,
either in success or in error.
This variant of guaranteeCase evaluates the given finalizer
regardless of how the source gets terminated:
This equivalence always holds:
io.guarantee(f) <-> IO.unit.bracket(_ => io)(_ => f)
As best practice, it's not a good idea to release resources
via guaranteeCase
in polymorphic code. Prefer bracket
for the acquisition and release of resources.
bracket for the more general operation
guaranteeCase for the version that can discriminate between termination conditions
Executes the given finalizer
when the source is finished,
either in success or in error, allowing
for differentiating between exit conditions.
Executes the given finalizer
when the source is finished,
either in success or in error, allowing
for differentiating between exit conditions.
This variant of guarantee injects an ExitCase in the provided function, allowing one to make a difference between:
This equivalence always holds:
io.guaranteeCase(f) <-> IO.unit.bracketCase(_ => io)((_, e) => f(e))
As best practice, it's not a good idea to release resources
via guaranteeCase
in polymorphic code. Prefer bracketCase
for the acquisition and release of resources.
bracketCase for the more general operation
guarantee for the simpler version
Handle any error, potentially recovering from it, by mapping it to another
SyncIO
value.
Handle any error, potentially recovering from it, by mapping it to another
SyncIO
value.
Implements ApplicativeError.handleErrorWith
.
Functor map on SyncIO
.
Functor map on SyncIO
. Given a mapping function, it transforms the
value produced by the source, while keeping the SyncIO
context.
Any exceptions thrown within the function will be caught and
sequenced in to the result SyncIO[B]
.
Returns a new value that transforms the result of the source,
given the recover
or map
functions, which get executed depending
on whether the result is successful or if it ends in error.
Returns a new value that transforms the result of the source,
given the recover
or map
functions, which get executed depending
on whether the result is successful or if it ends in error.
This is an optimization on usage of attempt and map, this equivalence being true:
io.redeem(recover, map) <-> io.attempt.map(_.fold(recover, map))
Usage of redeem
subsumes handleError
because:
io.redeem(fe, id) <-> io.handleError(fe)
is a function used for error recover in case the source ends in error
is a function used for mapping the result of the source in case it ends in success
Returns a new value that transforms the result of the source,
given the recover
or bind
functions, which get executed depending
on whether the result is successful or if it ends in error.
Returns a new value that transforms the result of the source,
given the recover
or bind
functions, which get executed depending
on whether the result is successful or if it ends in error.
This is an optimization on usage of attempt and flatMap, this equivalence being available:
io.redeemWith(recover, bind) <-> io.attempt.flatMap(_.fold(recover, bind))
Usage of redeemWith
subsumes handleErrorWith
because:
io.redeemWith(fe, F.pure) <-> io.handleErrorWith(fe)
Usage of redeemWith
also subsumes flatMap because:
io.redeemWith(F.raiseError, fs) <-> io.flatMap(fs)
is the function that gets called to recover the source in case of error
is the function that gets to transform the source in case of success
Converts the source IO
into any F
type that implements
the LiftIO type class.
Produces the result by running the encapsulated effects as impure side effects.
Produces the result by running the encapsulated effects as impure side effects.
Any exceptions raised within the effect will be re-thrown during evaluation.
As the name says, this is an UNSAFE function as it is impure and performs side effects and throws exceptions. You should ideally only call this function *once*, at the very end of your program.
A pure abstraction representing the intention to perform a side effect, where the result of that side effect is obtained synchronously.
SyncIO
is similar to IO, but does not support asynchronous computations. Consequently, aSyncIO
can be run synchronously to obtain a result viaunsafeRunSync
. This is unlikeIO#unsafeRunSync
, which cannot be safely called in general -- doing so on the JVM blocks the calling thread while the async part of the computation is run and doing so on Scala.JS throws an exception upon encountering an async boundary.